Ansible AWX API — Automate Jobs Templates and Inventories

Introduction

AWX (the upstream of Ansible Automation Platform Controller) provides a REST API for programmatic control of your automation. With the awx.awx collection or direct API calls via the uri module, you can launch jobs, manage inventories, sync projects, and orchestrate workflows — all from Ansible playbooks or CI/CD pipelines.

Prerequisites

# Install the AWX collection
ansible-galaxy collection install awx.awx

# Install the CLI (optional)
pip install awxkit
# Connection variables (use Vault for token/password)
awx_url: "https://awx.example.com"
awx_token: "{{ vault_awx_api_token }}"
# Or username/password:
awx_user: admin
awx_password: "{{ vault_awx_password }}"

Authentication

---
- name: AWX API examples
  hosts: localhost
  connection: local
  vars:
    awx_host: "https://awx.example.com"
    awx_token: "{{ vault_awx_token }}"

  tasks:
    # Method 1: OAuth2 Token (recommended)
    - name: Get API version
      ansible.builtin.uri:
        url: "{{ awx_host }}/api/v2/ping/"
        headers:
          Authorization: "Bearer {{ awx_token }}"
        validate_certs: true
      register: api_ping

    - name: Show AWX version
      ansible.builtin.debug:
        msg: "AWX version: {{ api_ping.json.version }}"

Launch a Job Template

    # Using awx.awx collection (recommended)
    - name: Launch job template
      awx.awx.job_launch:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        job_template: "Deploy Web Application"
        extra_vars:
          app_version: "2.1.0"
          environment: production
        limit: "web01,web02"
        tags: deploy,restart
      register: job

    - name: Wait for job completion
      awx.awx.job_wait:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        job_id: "{{ job.id }}"
        timeout: 600
      register: job_result

    - name: Show job status
      ansible.builtin.debug:
        msg: "Job {{ job.id }}: {{ job_result.status }}"

Via REST API Directly

    - name: Launch job via REST API
      ansible.builtin.uri:
        url: "{{ awx_host }}/api/v2/job_templates/42/launch/"
        method: POST
        headers:
          Authorization: "Bearer {{ awx_token }}"
          Content-Type: application/json
        body_format: json
        body:
          extra_vars:
            app_version: "2.1.0"
          limit: "web01"
        status_code: 201
      register: launched_job

    - name: Poll job status until complete
      ansible.builtin.uri:
        url: "{{ awx_host }}/api/v2/jobs/{{ launched_job.json.id }}/"
        headers:
          Authorization: "Bearer {{ awx_token }}"
      register: job_status
      until: job_status.json.status in ['successful', 'failed', 'error', 'canceled']
      retries: 60
      delay: 10

Manage Inventories

    - name: Create inventory
      awx.awx.inventory:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "Production Servers"
        organization: "Default"
        description: "Production infrastructure"
        state: present

    - name: Add host to inventory
      awx.awx.host:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "web03"
        inventory: "Production Servers"
        variables:
          ansible_host: 192.168.1.13
          ansible_user: deploy
        state: present

    - name: Create inventory source (dynamic)
      awx.awx.inventory_source:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "AWS EC2"
        inventory: "Production Servers"
        source: ec2
        credential: "AWS Credentials"
        source_vars:
          regions: us-east-1,eu-west-1
          filters:
            tag:Environment: production
        update_on_launch: true
        state: present

Manage Credentials

    - name: Create machine credential
      awx.awx.credential:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "Production SSH Key"
        organization: "Default"
        credential_type: "Machine"
        inputs:
          username: deploy
          ssh_key_data: "{{ lookup('file', '~/.ssh/prod_key') }}"
          become_method: sudo
          become_username: root
        state: present

    - name: Create SCM credential
      awx.awx.credential:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "GitHub Token"
        organization: "Default"
        credential_type: "Source Control"
        inputs:
          username: git-token
          password: "{{ vault_github_token }}"
        state: present

Manage Job Templates

    - name: Create job template
      awx.awx.job_template:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "Deploy Web Application"
        organization: "Default"
        project: "Infrastructure"
        playbook: "playbooks/deploy.yml"
        inventory: "Production Servers"
        credentials:
          - "Production SSH Key"
        extra_vars:
          app_version: latest
        ask_variables_on_launch: true
        ask_limit_on_launch: true
        ask_tags_on_launch: true
        state: present

Workflows

    - name: Create workflow template
      awx.awx.workflow_job_template:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        name: "Full Deploy Pipeline"
        organization: "Default"
        state: present

    - name: Add workflow nodes
      awx.awx.workflow_job_template_node:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        workflow_job_template: "Full Deploy Pipeline"
        identifier: "deploy"
        unified_job_template: "Deploy Web Application"
        success_nodes:
          - "smoke_test"

    - name: Launch workflow
      awx.awx.workflow_launch:
        controller_host: "{{ awx_host }}"
        controller_oauthtoken: "{{ awx_token }}"
        workflow_template: "Full Deploy Pipeline"
        extra_vars:
          app_version: "2.1.0"
      register: workflow

CI/CD Integration

# .github/workflows/deploy.yml
name: Deploy via AWX
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger AWX job
        run: |
          curl -X POST \
            -H "Authorization: Bearer ${{ secrets.AWX_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d '{"extra_vars": {"version": "${{ github.sha }}"}}' \
            "https://awx.example.com/api/v2/job_templates/42/launch/"

Troubleshooting

IssueSolution
401 UnauthorizedCheck token validity; regenerate at /api/v2/tokens/
403 ForbiddenUser lacks permission on the resource
Job stays pendingCheck available execution instances; scale AWX
Inventory sync failsVerify credentials and source configuration
Workflow node failsCheck individual job template runs independently first

Best Practices

  1. Use OAuth2 tokens over basic auth — tokens can be scoped and revoked
  2. Use awx.awx collection over raw API — handles pagination and errors
  3. Store credentials in AWX — not in playbooks or CI/CD variables
  4. Use workflows for multi-step deployments — built-in success/failure branching
  5. Enable webhook triggers — AWX can listen for GitHub/GitLab webhooks directly
  6. Audit via API — query /api/v2/jobs/ for deployment history

Conclusion

The AWX API turns your Ansible automation into a programmable service. Whether triggered from CI/CD pipelines, chatops, or other playbooks, you can launch jobs, manage infrastructure, and orchestrate complex workflows — all through a consistent REST interface backed by the awx.awx collection.