> ## Documentation Index
> Fetch the complete documentation index at: https://platform-docs.sarj.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Place an outbound Sarj.ai voice call

> Place an outbound Sarj.ai voice call: dials the given phone_number and runs the specified scenario (with optional template variables and language). Returns a call_id that can be polled via getCall. Use this whenever the user asks to call, dial, ring, or phone someone through Sarj.ai — do not attempt to start calls by writing to the database or invoking telephony providers directly.



## OpenAPI

````yaml /api-reference/openapi.json post /calls
openapi: 3.1.0
info:
  title: Sarj.ai Developer API
  description: >
    Public API for programmatic access to the **Sarj.ai voice platform**.


    > [!TIP]

    > **New here?** Start with the [Getting Started
    guide](https://platform-docs.sarj.ai/getting-started)

    > to go from API key to first call in under 5 minutes.

    >

    > **Building with AI agents?** See the [MCP Server
    guide](https://platform-docs.sarj.ai/mcp-server)

    > to connect Claude Code, Cursor, or any MCP-compatible agent.


    ---


    ## Authentication


    All authenticated endpoints require a **Bearer token** in the
    `Authorization`

    header:


    ```

    Authorization: Bearer <your-api-key>

    ```


    Generate an API key from
    [platform.sarj.ai/api-keys](https://platform.sarj.ai/api-keys).


    > [!WARNING]

    > If you receive a `401 Unauthorized` response, your key may be invalid,

    > expired, or missing. Check the `error.type` field in the response body.


    ---


    ## Response Format


    **Success**


    ```json

    {
      "data": { ... },
      "meta": { "request_id": "550e8400-e29b-41d4-a716-446655440000" }
    }

    ```


    **Error**


    ```json

    {
      "error": {
        "type": "unauthorized",
        "message": "Authentication required."
      },
      "meta": { "request_id": "550e8400-e29b-41d4-a716-446655440000" }
    }

    ```


    Always branch on `error.type` — the `message` field is for humans only.


    ---


    ## Support


    Include `meta.request_id` in all support tickets for faster resolution.
  license:
    name: Apache 2.0
    identifier: Apache-2.0
  version: 1.1.0
servers:
  - url: https://platform-api.sarj.ai/api/v1
    description: Production
security:
  - ApiKeyAuth: []
tags:
  - name: System
    description: Service health and status.
  - name: Calls
    description: Create outbound voice calls and retrieve call details and transcripts.
  - name: Schedule Configs
    description: Create and manage retry policies for scheduled outbound calls.
externalDocs:
  description: Sarj.ai Documentation
  url: https://platform-docs.sarj.ai
paths:
  /calls:
    post:
      tags:
        - Calls
      summary: Place an outbound Sarj.ai voice call
      description: >-
        Place an outbound Sarj.ai voice call: dials the given phone_number and
        runs the specified scenario (with optional template variables and
        language). Returns a call_id that can be polled via getCall. Use this
        whenever the user asks to call, dial, ring, or phone someone through
        Sarj.ai — do not attempt to start calls by writing to the database or
        invoking telephony providers directly.
      operationId: createCall
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCallRequest'
        required: true
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse_PublicCall_'
              example:
                data:
                  id: call_8f9b2c1e-4a5d-4f6e-8b1a-2c3d4e5f6a7b
                  status: queued
                  phone_number: '+966512345678'
                  scenario_id: scn_abc123
                  created_at: '2026-04-12T10:30:00Z'
                meta:
                  request_id: 550e8400-e29b-41d4-a716-446655440000
        '400':
          description: Outbound call failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  type: outbound_call_failed
                  message: Outbound call could not be initiated.
                  reason: telephony_provider_unavailable
                meta:
                  request_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  type: unauthorized
                  message: Authentication required.
                meta: {}
        '403':
          description: >-
            Forbidden — phone number blocked, scenario access denied, or
            scheduling (scheduled_at or schedule_config_id) is disabled on this
            environment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                phone_number_blocked:
                  summary: Phone number is blocked
                  value:
                    error:
                      type: phone_number_blocked
                      message: Phone number +966512345678 is blocked.
                      phone_number: '+966512345678'
                    meta:
                      request_id: 550e8400-e29b-41d4-a716-446655440000
                scenario_forbidden:
                  summary: Scenario belongs to a different organization
                  value:
                    error:
                      type: scenario_forbidden
                      message: Access denied to scenario scn_abc123.
                      scenario_id: scn_abc123
                    meta:
                      request_id: 550e8400-e29b-41d4-a716-446655440000
                scheduling_disabled:
                  summary: Call scheduling is not enabled on this environment
                  value:
                    error:
                      type: scheduling_disabled
                      message: Call scheduling is not enabled on this environment.
                    meta:
                      request_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: >-
            Scenario not found, or the requested schedule_config_id does not
            exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                scenario_not_found:
                  summary: Scenario does not exist
                  value:
                    error:
                      type: scenario_not_found
                      message: Scenario scn_abc123 was not found.
                      scenario_id: scn_abc123
                    meta:
                      request_id: 550e8400-e29b-41d4-a716-446655440000
                schedule_config_not_found:
                  summary: Requested schedule_config_id does not exist
                  value:
                    error:
                      type: schedule_config_not_found
                      message: >-
                        Schedule config 01890000-0000-7000-8000-000000000000 was
                        not found.
                      schedule_config_id: 01890000-0000-7000-8000-000000000000
                    meta:
                      request_id: 550e8400-e29b-41d4-a716-446655440000
        '422':
          description: Validation error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  type: validation_error
                  message: Request validation failed.
                  field_violations:
                    - field: body.phone_number
                      message: value is not a valid phone number
                meta:
                  request_id: 550e8400-e29b-41d4-a716-446655440000
        '429':
          description: Call limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  type: call_limit_exceeded
                  message: Call limit of 10 reached for phone number +966512345678.
                  phone_number: '+966512345678'
                  call_limit: 10
                meta:
                  request_id: 550e8400-e29b-41d4-a716-446655440000
        '500':
          description: Unexpected server error with a request ID for support correlation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      x-codeSamples:
        - label: Python (SDK)
          lang: Python
          source: |-
            import os
            from sarj_platform_sdk import SDK

            sdk = SDK(api_key_auth=os.environ["SARJ_API_KEY"])
            res = sdk.calls.create_call(
                phone_number="+966512345678",
                scenario_id="scn_abc123",
                language="ar",
            )
            print(f"Call queued: {res.data.id}")
        - label: curl
          lang: bash
          source: |-
            curl -X POST https://platform-api.sarj.ai/api/v1/calls \
              -H "Authorization: Bearer $SARJ_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "phone_number": "+966512345678",
                "scenario_id": "scn_abc123",
                "language": "ar"
              }'
        - label: Python (requests)
          lang: Python
          source: |-
            import os
            import requests

            response = requests.post(
                "https://platform-api.sarj.ai/api/v1/calls",
                headers={
                    "Authorization": f"Bearer {os.environ['SARJ_API_KEY']}",
                },
                json={
                    "phone_number": "+966512345678",
                    "scenario_id": "scn_abc123",
                    "language": "ar",
                },
            )
            response.raise_for_status()
            call = response.json()["data"]
            print(f"Call queued: {call['id']}")
        - label: TypeScript
          lang: TypeScript
          source: >-
            const response = await
            fetch("https://platform-api.sarj.ai/api/v1/calls", {
              method: "POST",
              headers: {
                "Authorization": `Bearer ${process.env.SARJ_API_KEY}`,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                phone_number: "+966512345678",
                scenario_id: "scn_abc123",
                language: "ar",
              }),
            });


            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            const { data: call } = await response.json();

            console.log(`Call queued: ${call.id}`);
components:
  schemas:
    CreateCallRequest:
      properties:
        phone_number:
          type: string
          title: Phone Number
          description: Phone number to call in E.164 format.
          examples:
            - '+966512345678'
        scenario_id:
          type: string
          minLength: 1
          title: Scenario Id
          description: ID of the scenario to use for this call.
        variables:
          additionalProperties: true
          type: object
          title: Variables
          description: Template variables to inject into the scenario.
        language:
          $ref: '#/components/schemas/Language'
          description: Language for the call. Defaults to Arabic (ar) if not specified.
          default: ar
        scheduled_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Scheduled At
          description: >-
            Book the call for a future time (RFC 3339 with timezone offset)
            instead of dialing now. Must be at least 10 minutes ahead and within
            30 days. The call is created with status 'scheduled' and dialed when
            due; cancel or reschedule it via the corresponding endpoints while
            pending.
          examples:
            - '2026-05-01T15:30:00+03:00'
        schedule_config_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Schedule Config Id
          description: >-
            Retry rules for this call, referencing a config created via
            createScheduleConfig. Omitted, the scenario's default schedule
            config applies automatically when one is configured.
          examples:
            - 01890000-0000-7000-8000-000000000000
      additionalProperties: false
      type: object
      required:
        - phone_number
        - scenario_id
      title: CreateCallRequest
    ApiResponse_PublicCall_:
      properties:
        data:
          $ref: '#/components/schemas/PublicCall'
        meta:
          $ref: '#/components/schemas/ResponseMeta'
      additionalProperties: false
      type: object
      required:
        - data
        - meta
      title: ApiResponse[PublicCall]
    ErrorResponse:
      properties:
        error:
          oneOf:
            - $ref: '#/components/schemas/ValidationErrorPayload'
            - $ref: '#/components/schemas/UnauthorizedPayload'
            - $ref: '#/components/schemas/NotFoundPayload'
            - $ref: '#/components/schemas/InternalErrorPayload'
            - $ref: '#/components/schemas/PhoneNumberBlockedPayload'
            - $ref: '#/components/schemas/CallLimitExceededPayload'
            - $ref: '#/components/schemas/OutboundCallFailedPayload'
            - $ref: '#/components/schemas/ScenarioNotFoundPayload'
            - $ref: '#/components/schemas/ScenarioForbiddenPayload'
            - $ref: '#/components/schemas/ScenarioInvalidConfigPayload'
            - $ref: '#/components/schemas/NoOrganizationPayload'
            - $ref: '#/components/schemas/CallNotFoundPayload'
            - $ref: '#/components/schemas/OauthInvalidRedirectUriPayload'
            - $ref: '#/components/schemas/SchedulingDisabledPayload'
            - $ref: '#/components/schemas/InvalidScheduleTimePayload'
            - $ref: '#/components/schemas/ScheduleConfigNotFoundPayload'
            - $ref: '#/components/schemas/CallNotPendingPayload'
          title: Error
          discriminator:
            propertyName: type
            mapping:
              call_limit_exceeded: '#/components/schemas/CallLimitExceededPayload'
              call_not_found: '#/components/schemas/CallNotFoundPayload'
              call_not_pending: '#/components/schemas/CallNotPendingPayload'
              internal_error: '#/components/schemas/InternalErrorPayload'
              invalid_schedule_time: '#/components/schemas/InvalidScheduleTimePayload'
              no_organization: '#/components/schemas/NoOrganizationPayload'
              not_found: '#/components/schemas/NotFoundPayload'
              oauth_invalid_redirect_uri: '#/components/schemas/OauthInvalidRedirectUriPayload'
              outbound_call_failed: '#/components/schemas/OutboundCallFailedPayload'
              phone_number_blocked: '#/components/schemas/PhoneNumberBlockedPayload'
              scenario_forbidden: '#/components/schemas/ScenarioForbiddenPayload'
              scenario_invalid_config: '#/components/schemas/ScenarioInvalidConfigPayload'
              scenario_not_found: '#/components/schemas/ScenarioNotFoundPayload'
              schedule_config_not_found: '#/components/schemas/ScheduleConfigNotFoundPayload'
              scheduling_disabled: '#/components/schemas/SchedulingDisabledPayload'
              unauthorized: '#/components/schemas/UnauthorizedPayload'
              validation_error: '#/components/schemas/ValidationErrorPayload'
        meta:
          $ref: '#/components/schemas/ResponseMeta'
      additionalProperties: false
      type: object
      required:
        - error
        - meta
      title: ErrorResponse
      description: >-
        Standard envelope for all public API error responses.


        `error` is a discriminated union — branch on `error.type` to access

        variant-specific fields. Generated clients preserve unknown tagged
        variants

        so applications can log and surface newer server errors safely.
    Language:
      type: string
      enum:
        - en
        - ar
        - ur
      title: Language
      description: Language codes in ISO 639-1
    PublicCall:
      properties:
        id:
          type: string
          title: Id
          description: Unique call identifier.
          examples:
            - call_550e8400-e29b-41d4-a716-446655440000
        status:
          $ref: '#/components/schemas/CallStatus'
          description: Current call status.
          examples:
            - queued
        phone_number:
          type: string
          title: Phone Number
          description: Destination phone number.
        scenario_id:
          type: string
          title: Scenario Id
          description: Scenario used for this call.
        created_at:
          type: string
          format: date-time
          title: Created At
          description: >-
            Timestamp when the call was created. For a scheduled call this is
            booking time, not dial time.
        scheduled_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Scheduled At
          description: When a scheduled call is booked to dial. Null for immediate calls.
        booking_outcome:
          anyOf:
            - type: string
              enum:
                - created
                - rescheduled_existing
                - kept_existing
            - type: 'null'
          title: Booking Outcome
          description: >-
            Only present on the createCall booking (202) response. 'created' is
            a new booking; 'rescheduled_existing' or 'kept_existing' means an
            existing pending call for the same scenario+phone was taken over or
            kept, and the returned id/scheduled_at are that existing call's —
            check it rather than assuming a second call now exists.
      additionalProperties: false
      type: object
      required:
        - id
        - status
        - phone_number
        - scenario_id
        - created_at
      title: PublicCall
    ResponseMeta:
      properties:
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Id
          description: >-
            Unique identifier for this request, mirrored in the `X-Request-ID`
            response header. Supply your own via the `X-Request-ID` request
            header (max 128 chars, ASCII printable); otherwise the server
            generates a UUID v4. Include in support tickets.
          examples:
            - 550e8400-e29b-41d4-a716-446655440000
      additionalProperties: false
      type: object
      title: ResponseMeta
      description: Contains request-level metadata included with every public API response.
    ValidationErrorPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: validation_error
          title: Type
          default: validation_error
        field_violations:
          items:
            $ref: '#/components/schemas/FieldViolation'
          type: array
          title: Field Violations
          description: Per-field validation details.
      additionalProperties: false
      type: object
      required:
        - message
        - field_violations
        - type
      title: ValidationErrorPayload
    UnauthorizedPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: unauthorized
          title: Type
          default: unauthorized
      additionalProperties: false
      type: object
      required:
        - message
        - type
      title: UnauthorizedPayload
    NotFoundPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: not_found
          title: Type
          default: not_found
      additionalProperties: false
      type: object
      required:
        - message
        - type
      title: NotFoundPayload
    InternalErrorPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: internal_error
          title: Type
          default: internal_error
      additionalProperties: false
      type: object
      required:
        - message
        - type
      title: InternalErrorPayload
    PhoneNumberBlockedPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: phone_number_blocked
          title: Type
          default: phone_number_blocked
        phone_number:
          type: string
          title: Phone Number
          description: The phone number that is blocked.
      additionalProperties: false
      type: object
      required:
        - message
        - phone_number
        - type
      title: PhoneNumberBlockedPayload
    CallLimitExceededPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: call_limit_exceeded
          title: Type
          default: call_limit_exceeded
        phone_number:
          type: string
          title: Phone Number
          description: The phone number that hit the limit.
        call_limit:
          type: integer
          title: Call Limit
          description: The per-number call limit that was reached.
      additionalProperties: false
      type: object
      required:
        - message
        - phone_number
        - call_limit
        - type
      title: CallLimitExceededPayload
    OutboundCallFailedPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: outbound_call_failed
          title: Type
          default: outbound_call_failed
        reason:
          type: string
          title: Reason
          description: Stable-ish reason string from the call service.
      additionalProperties: false
      type: object
      required:
        - message
        - reason
        - type
      title: OutboundCallFailedPayload
    ScenarioNotFoundPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: scenario_not_found
          title: Type
          default: scenario_not_found
        scenario_id:
          type: string
          title: Scenario Id
      additionalProperties: false
      type: object
      required:
        - message
        - scenario_id
        - type
      title: ScenarioNotFoundPayload
    ScenarioForbiddenPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: scenario_forbidden
          title: Type
          default: scenario_forbidden
        scenario_id:
          type: string
          title: Scenario Id
      additionalProperties: false
      type: object
      required:
        - message
        - scenario_id
        - type
      title: ScenarioForbiddenPayload
    ScenarioInvalidConfigPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: scenario_invalid_config
          title: Type
          default: scenario_invalid_config
        scenario_id:
          type: string
          title: Scenario Id
      additionalProperties: false
      type: object
      required:
        - message
        - scenario_id
        - type
      title: ScenarioInvalidConfigPayload
    NoOrganizationPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: no_organization
          title: Type
          default: no_organization
      additionalProperties: false
      type: object
      required:
        - message
        - type
      title: NoOrganizationPayload
    CallNotFoundPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: call_not_found
          title: Type
          default: call_not_found
        call_id:
          type: string
          title: Call Id
      additionalProperties: false
      type: object
      required:
        - message
        - call_id
        - type
      title: CallNotFoundPayload
    OauthInvalidRedirectUriPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: oauth_invalid_redirect_uri
          title: Type
          default: oauth_invalid_redirect_uri
        redirect_uri:
          type: string
          title: Redirect Uri
      additionalProperties: false
      type: object
      required:
        - message
        - redirect_uri
        - type
      title: OauthInvalidRedirectUriPayload
    SchedulingDisabledPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: scheduling_disabled
          title: Type
          default: scheduling_disabled
      additionalProperties: false
      type: object
      required:
        - message
        - type
      title: SchedulingDisabledPayload
    InvalidScheduleTimePayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: invalid_schedule_time
          title: Type
          default: invalid_schedule_time
      additionalProperties: false
      type: object
      required:
        - message
        - type
      title: InvalidScheduleTimePayload
    ScheduleConfigNotFoundPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: schedule_config_not_found
          title: Type
          default: schedule_config_not_found
        schedule_config_id:
          type: string
          title: Schedule Config Id
      additionalProperties: false
      type: object
      required:
        - message
        - schedule_config_id
        - type
      title: ScheduleConfigNotFoundPayload
    CallNotPendingPayload:
      properties:
        message:
          type: string
          title: Message
          description: >-
            Human-readable summary. Do not parse programmatically — branch on
            `type`.
        type:
          type: string
          const: call_not_pending
          title: Type
          default: call_not_pending
        status:
          anyOf:
            - type: string
            - type: 'null'
          title: Status
      additionalProperties: false
      type: object
      required:
        - message
        - status
        - type
      title: CallNotPendingPayload
    CallStatus:
      type: string
      enum:
        - queued
        - in_progress
        - transferring
        - transferred
        - completed
        - timeout
        - user_rejected
        - max_duration_reached
        - failed
        - ringing
        - voicemail
        - dialing
        - cancelled
        - expired
        - scheduled
      title: CallStatus
    FieldViolation:
      properties:
        field:
          type: string
          title: Field
          description: >-
            Dot-separated path to the invalid field (e.g.
            `phone_number.country_code`).
          examples:
            - phone_number.country_code
        message:
          type: string
          title: Message
          description: Human-readable description of the violation.
          examples:
            - Must start with +
      additionalProperties: false
      type: object
      required:
        - field
        - message
      title: FieldViolation
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: >-
        API key from your Sarj.ai dashboard. Pass as: Authorization: Bearer
        <api-key>

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.