diff --git a/README.md b/README.md
index 49e15ab1..15a1da13 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ Name | Description |
[linode.cloud.firewall_device](./docs/modules/firewall_device.md)|Manage Linode Firewall Devices.|
[linode.cloud.image](./docs/modules/image.md)|Manage a Linode Image.|
[linode.cloud.instance](./docs/modules/instance.md)|Manage Linode Instances, Configs, and Disks.|
+[linode.cloud.ip](./docs/modules/ip.md)|Allocates a new IPv4 Address on your Account. The Linode must be configured to support additional addresses - please Open a support ticket requesting additional addresses before attempting allocation.|
[linode.cloud.ip_assign](./docs/modules/ip_assign.md)|Assign IPs to Linodes in a given Region.|
[linode.cloud.ip_rdns](./docs/modules/ip_rdns.md)|Manage a Linode IP address's rDNS.|
[linode.cloud.ip_share](./docs/modules/ip_share.md)|Manage the Linode shared IPs.|
diff --git a/docs/modules/ip.md b/docs/modules/ip.md
new file mode 100644
index 00000000..f9175fce
--- /dev/null
+++ b/docs/modules/ip.md
@@ -0,0 +1,38 @@
+# ip
+
+Allocates a new IPv4 Address on your Account. The Linode must be configured to support additional addresses - please Open a support ticket requesting additional addresses before attempting allocation.
+
+- [Minimum Required Fields](#minimum-required-fields)
+- [Examples](#examples)
+- [Parameters](#parameters)
+- [Return Values](#return-values)
+
+## Minimum Required Fields
+| Field | Type | Required | Description |
+|-------------|-------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `api_token` | `str` | **Required** | The Linode account personal access token. It is necessary to run the module.
It can be exposed by the environment variable `LINODE_API_TOKEN` instead.
See details in [Usage](https://github.com/linode/ansible_linode?tab=readme-ov-file#usage). |
+
+## Examples
+
+```yaml
+- name: Allocate IP to Linode
+ linode.cloud.ip:
+ linode_id: 123
+ public: true
+ type: ipv4
+ state: present
+```
+
+
+## Parameters
+
+| Field | Type | Required | Description |
+|-----------|------|----------|------------------------------------------------------------------------------|
+| `state` |
`str` | **Required** | The state of this IP. **(Choices: `present`, `absent`)** |
+| `linode_id` | `int` | Optional | The ID of a Linode you have access to that this address will be allocated to. |
+| `public` | `bool` | Optional | Whether to create a public or private IPv4 address. |
+| `type` | `str` | Optional | The type of address you are requesting. Only IPv4 addresses may be allocated through this operation. **(Choices: `ipv4`)** |
+| `address` | `str` | Optional | The IP address to delete. **(Conflicts With: `linode_id`,`public`,`type`)** |
+
+## Return Values
+
diff --git a/plugins/module_utils/doc_fragments/ip.py b/plugins/module_utils/doc_fragments/ip.py
new file mode 100644
index 00000000..aefaed91
--- /dev/null
+++ b/plugins/module_utils/doc_fragments/ip.py
@@ -0,0 +1,25 @@
+"""Documentation fragments for the ip module"""
+specdoc_examples = ['''
+- name: Allocate IP to Linode
+ linode.cloud.ip:
+ linode_id: 123
+ public: true
+ type: ipv4
+ state: present''']
+
+result_ip_samples = ['''{
+ "address": "97.107.143.141",
+ "gateway": "97.107.143.1",
+ "linode_id": 123,
+ "prefix": 24,
+ "public": true,
+ "rdns": "test.example.org",
+ "region": "us-east",
+ "subnet_mask": "255.255.255.0",
+ "type": "ipv4",
+ "vpc_nat_1_1": {
+ "vpc_id": 242,
+ "subnet_id": 194,
+ "address": "139.144.244.36"
+ }
+}''']
diff --git a/plugins/modules/ip.py b/plugins/modules/ip.py
new file mode 100644
index 00000000..073d437d
--- /dev/null
+++ b/plugins/modules/ip.py
@@ -0,0 +1,137 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""This module allows users to allocate a new IPv4 Address on their accounts."""
+
+from __future__ import absolute_import, division, print_function
+
+from typing import Any, Optional
+
+import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.ip as docs
+from ansible_collections.linode.cloud.plugins.module_utils.linode_common import (
+ LinodeModuleBase,
+)
+from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import (
+ global_authors,
+ global_requirements,
+)
+from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import (
+ filter_null_values,
+)
+from ansible_specdoc.objects import FieldType, SpecDocMeta, SpecField
+
+spec: dict = {
+ "linode_id": SpecField(
+ type=FieldType.integer,
+ description=[
+ "The ID of a Linode you have access to "
+ "that this address will be allocated to."
+ ],
+ ),
+ "public": SpecField(
+ type=FieldType.bool,
+ description=["Whether to create a public or private IPv4 address."],
+ ),
+ "type": SpecField(
+ type=FieldType.string,
+ choices=["ipv4"],
+ description=[
+ "The type of address you are requesting. "
+ "Only IPv4 addresses may be allocated through this operation."
+ ],
+ ),
+ "address": SpecField(
+ type=FieldType.string,
+ description=["The IP address to delete."],
+ conflicts_with=["linode_id", "public", "type"],
+ ),
+ "state": SpecField(
+ type=FieldType.string,
+ choices=["present", "absent"],
+ required=True,
+ description=["The state of this IP."],
+ ),
+}
+
+SPECDOC_META = SpecDocMeta(
+ description=[
+ "Allocates a new IPv4 Address on your Account. "
+ "The Linode must be configured to support "
+ "additional addresses - "
+ "please Open a support ticket "
+ "requesting additional addresses before attempting allocation.",
+ ],
+ requirements=global_requirements,
+ author=global_authors,
+ options=spec,
+ examples=docs.specdoc_examples,
+ return_values={},
+)
+
+DOCUMENTATION = r"""
+"""
+EXAMPLES = r"""
+"""
+RETURN = r"""
+"""
+
+
+class Module(LinodeModuleBase):
+ """Module for allocating a new IP"""
+
+ def __init__(self) -> None:
+ self.module_arg_spec = SPECDOC_META.ansible_spec
+ self.results = {
+ "changed": False,
+ "actions": [],
+ "ip": None,
+ }
+ super().__init__(
+ module_arg_spec=self.module_arg_spec,
+ required_together=[
+ ("linode_id", "public", "type"),
+ ],
+ )
+
+ def _handle_present(self) -> None:
+ params = filter_null_values(self.module.params)
+ linode_id = params.get("linode_id")
+ public = params.get("public")
+
+ try:
+ ip = self.client.networking.ip_allocate(linode_id, public)
+ self.register_action(
+ f"IP allocation to Linode {linode_id} completed."
+ )
+ except Exception as exc:
+ self.fail(msg=f"failed to allocate IP to Linode {linode_id}: {exc}")
+
+ self.results["ip"] = ip._raw_json
+
+ def _handle_absent(self) -> None:
+ # TODO: Implement deleting IP once it's available in python-sdk.
+ # Raise an error for now when user reaches deleting IP.
+ self.fail(
+ msg="failed to delete IP: IP deleting is currently not supported."
+ )
+
+ def exec_module(self, **kwargs: Any) -> Optional[dict]:
+ """Entrypoint for IP module"""
+
+ state = kwargs.get("state")
+
+ if state == "absent":
+ self._handle_absent()
+ return self.results
+
+ self._handle_present()
+
+ return self.results
+
+
+def main() -> None:
+ """Constructs and calls the module"""
+ Module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/integration/targets/ip_basic/tasks/main.yaml b/tests/integration/targets/ip_basic/tasks/main.yaml
new file mode 100644
index 00000000..ce9e7524
--- /dev/null
+++ b/tests/integration/targets/ip_basic/tasks/main.yaml
@@ -0,0 +1,53 @@
+- name: ip
+ block:
+ - set_fact:
+ r: "{{ 1000000000 | random }}"
+
+ - name: Create a Linode Instance
+ linode.cloud.instance:
+ label: 'ansible-test-{{ r }}'
+ region: us-southeast
+ type: g6-standard-1
+ image: linode/alpine3.19
+ state: present
+ firewall_id: '{{ firewall_id }}'
+ register: create_instance
+
+ - name: Allocate a new IP to the Linode
+ linode.cloud.ip:
+ linode_id: '{{ create_instance.instance.id }}'
+ public: true
+ type: ipv4
+ state: present
+ register: allocate_ip
+
+ - name: Assert changes
+ assert:
+ that:
+ - allocate_ip.ip.linode_id == create_instance.instance.id
+ - allocate_ip.ip.type == 'ipv4'
+ - allocate_ip.ip.region == create_instance.instance.region
+
+# - name: Delete an IP
+# linode.cloud.ip:
+# address: allocate_ip.ip.address
+# state: absent
+# register: delete_ip
+
+ always:
+ - ignore_errors: true
+ block:
+ - name: Delete instance
+ linode.cloud.instance:
+ label: '{{ create_instance.instance.label }}'
+ state: absent
+
+
+ environment:
+ LINODE_UA_PREFIX: '{{ ua_prefix }}'
+ LINODE_API_TOKEN: '{{ api_token }}'
+ LINODE_API_URL: '{{ api_url }}'
+ LINODE_API_VERSION: '{{ api_version }}'
+ LINODE_CA: '{{ ca_file or "" }}'
+
+