Introduction
ansible.builtin.uri makes HTTP requests from your playbooks — call REST APIs, check health endpoints, download files, submit forms, and authenticate with tokens. It's Ansible's equivalent of curl.
Basic Requests
# GET request
- name: Check website
ansible.builtin.uri:
url: https://example.com
return_content: true
register: response
- debug:
msg: "Status: {{ response.status }}, Body: {{ response.content[:100] }}"
# Health check
- name: Check app health
ansible.builtin.uri:
url: http://localhost:8080/health
status_code: 200
Parameters
| Parameter | Default | Description |
|---|---|---|
url | (required) | Request URL |
method | GET | HTTP method |
body | — | Request body |
body_format | raw | json, form-urlencoded, form-multipart, raw |
headers | — | Request headers dict |
status_code | 200 | Expected status code(s) |
return_content | false | Include body in response |
timeout | 30 | Request timeout (seconds) |
validate_certs | true | Verify SSL certificates |
url_username | — | Basic auth username |
url_password | — | Basic auth password |
force_basic_auth | false | Send auth header preemptively |
dest | — | Download to file path |
creates | — | Skip if file exists |
follow_redirects | safe | all, safe, none |
POST Request (JSON)
# Create a resource
- name: Create user via API
ansible.builtin.uri:
url: https://api.example.com/users
method: POST
body_format: json
body:
name: "John Doe"
email: "john@example.com"
role: "admin"
headers:
Authorization: "Bearer {{ api_token }}"
status_code: [200, 201]
register: result
- debug:
msg: "Created user ID: {{ result.json.id }}"
PUT Request
- name: Update configuration
ansible.builtin.uri:
url: "https://api.example.com/config/{{ config_id }}"
method: PUT
body_format: json
body:
setting: "new_value"
enabled: true
headers:
Authorization: "Bearer {{ api_token }}"
status_code: 200
DELETE Request
- name: Delete resource
ansible.builtin.uri:
url: "https://api.example.com/resources/{{ resource_id }}"
method: DELETE
headers:
Authorization: "Bearer {{ api_token }}"
status_code: [200, 204]
Authentication
# Bearer token
- name: API call with token
ansible.builtin.uri:
url: https://api.example.com/data
headers:
Authorization: "Bearer {{ vault_api_token }}"
# Basic auth
- name: API with basic auth
ansible.builtin.uri:
url: https://api.example.com/data
url_username: "{{ api_user }}"
url_password: "{{ vault_api_password }}"
force_basic_auth: true
# API key in header
- name: API with key
ansible.builtin.uri:
url: https://api.example.com/data
headers:
X-API-Key: "{{ vault_api_key }}"
Download Files
- name: Download file
ansible.builtin.uri:
url: https://releases.example.com/app-v2.tar.gz
dest: /tmp/app-v2.tar.gz
creates: /tmp/app-v2.tar.gz # Skip if exists
Practical Patterns
Health Check with Retries
- name: Wait for app to be healthy
ansible.builtin.uri:
url: http://localhost:8080/health
status_code: 200
return_content: true
register: health
until: health.status == 200 and 'healthy' in (health.content | default(''))
retries: 30
delay: 10
API Pagination
- name: Fetch all pages
ansible.builtin.uri:
url: "https://api.example.com/items?page={{ item }}&per_page=100"
headers:
Authorization: "Bearer {{ api_token }}"
return_content: true
register: pages
loop: "{{ range(1, total_pages + 1) | list }}"
Webhook Notification
- name: Notify Slack
ansible.builtin.uri:
url: "{{ slack_webhook_url }}"
method: POST
body_format: json
body:
text: "Deployment of {{ app_version }} to {{ inventory_hostname }} completed ✅"
status_code: 200
- name: Notify Teams
ansible.builtin.uri:
url: "{{ teams_webhook_url }}"
method: POST
body_format: json
body:
"@type": MessageCard
summary: "Deploy Complete"
text: "{{ app_version }} deployed to {{ ansible_play_hosts | length }} hosts"
Deploy with API Calls
---
- name: Blue-Green Deployment
hosts: localhost
tasks:
- name: Remove server from load balancer
ansible.builtin.uri:
url: "https://lb.example.com/api/pools/web/members/{{ target_server }}"
method: DELETE
headers:
Authorization: "Bearer {{ lb_token }}"
status_code: [200, 204]
- name: Deploy to server
ansible.builtin.include_tasks: deploy.yml
- name: Wait for health check
ansible.builtin.uri:
url: "http://{{ target_server }}:8080/health"
status_code: 200
retries: 10
delay: 5
- name: Add server back to load balancer
ansible.builtin.uri:
url: "https://lb.example.com/api/pools/web/members"
method: POST
body_format: json
body:
address: "{{ target_server }}"
port: 8080
headers:
Authorization: "Bearer {{ lb_token }}"
status_code: [200, 201]
CRUD Operations
vars:
api_base: https://api.example.com
api_headers:
Authorization: "Bearer {{ vault_api_token }}"
Content-Type: application/json
tasks:
# Create
- name: Create item
ansible.builtin.uri:
url: "{{ api_base }}/items"
method: POST
body_format: json
body: { name: "widget", price: 9.99 }
headers: "{{ api_headers }}"
status_code: 201
register: created
# Read
- name: Get item
ansible.builtin.uri:
url: "{{ api_base }}/items/{{ created.json.id }}"
headers: "{{ api_headers }}"
return_content: true
# Update
- name: Update item
ansible.builtin.uri:
url: "{{ api_base }}/items/{{ created.json.id }}"
method: PUT
body_format: json
body: { price: 12.99 }
headers: "{{ api_headers }}"
# Delete
- name: Delete item
ansible.builtin.uri:
url: "{{ api_base }}/items/{{ created.json.id }}"
method: DELETE
headers: "{{ api_headers }}"
status_code: 204
Troubleshooting
SSL Certificate Errors
# Skip cert validation (dev/test only!)
- uri:
url: https://self-signed.example.com
validate_certs: false
Unexpected Status Code
# Accept multiple status codes
- uri:
url: https://api.example.com/resource
status_code: [200, 201, 204, 404]
register: result
- debug:
msg: "Resource {{ 'exists' if result.status != 404 else 'not found' }}"
Response Parsing
# JSON response is auto-parsed into .json
- uri:
url: https://api.example.com/data
return_content: true
register: result
- debug:
msg: "Name: {{ result.json.name }}, Count: {{ result.json.items | length }}"
Related Articles
- Ansible wait_for Module
- Ansible Variables Guide
- Ansible Vault for API Keys
- Ansible delegate_to Guide
Conclusion
ansible.builtin.uri is your HTTP client for automation. Use it for health checks, API integrations, webhook notifications, and deployment orchestration. Always store tokens and passwords in Vault. Use retries + delay for health checks that need time. Use status_code to accept expected responses. The body_format: json option handles serialization automatically. For anything you'd use curl for, use uri instead.