The missing link between Apple Business Manager and your asset inventory.
axm2snipe syncs every device from Apple Business Manager (ABM) or Apple School Manager (ASM) directly into Snipe-IT — no MDM required. It maps ABM device attributes, AppleCare coverage, purchase data, and MDM server assignments to fully populated Snipe-IT assets, keeping your inventory accurate and up to date automatically.
Inspired by jamf2snipe, but connects directly to Apple's device enrollment API instead of going through Jamf. If a device is in ABM or ASM, axm2snipe can sync it — whether or not it's enrolled in MDM.
- Syncs all devices from Apple Business Manager / Apple School Manager into Snipe-IT as hardware assets
- Matches existing Snipe-IT models by hardware identifier (e.g.
Mac16,10), marketing name, or part number - Automatically creates Snipe-IT asset models for new device types, with optional device images from appledb.dev
- Automatically creates Snipe-IT suppliers from ABM/ASM purchase sources
- Fetches AppleCare coverage details for each device
- Matches existing assets by serial number (create or update)
- Sync a single device by serial number with
sync --serial - Timestamp-based change detection to skip unchanged records
- Fully configurable field mapping between ABM/AppleCare attributes and Snipe-IT fields
- Filter by product family (Mac, iPhone, iPad, AppleTV, Watch, Vision)
- Update-only mode to sync data without creating new assets or models
- Resolves assigned MDM server name for each device
- Optional Slack webhook notifications when new assets are created
- Automatic setup of Snipe-IT custom fields with
setupcommand - Automatic retry with exponential backoff for API rate limits
- Dry-run mode with HTTP-level write protection
- MAC address auto-formatting (raw hex to colon-separated)
- Title-casing for colors and AppleCare values
- Sign in to Apple Business Manager or Apple School Manager
- Go to Settings > API
- Create a new API key and note the Client ID and Key ID
- Download the private key
.pemfile
- Generate an API key at Admin > API Keys
- Note the IDs for:
- Apple manufacturer (create one under Manufacturers if needed)
- Default status label for new assets
- Category for auto-created models (can be per product family)
- (Optional) Custom fieldset for ABM/AppleCare fields
Download a pre-built binary (recommended) from the latest release:
# macOS (Apple Silicon)
curl -L https://github.com/CampusTech/axm2snipe/releases/latest/download/axm2snipe-darwin-arm64 -o axm2snipe
chmod +x axm2snipe
# Linux (amd64)
curl -L https://github.com/CampusTech/axm2snipe/releases/latest/download/axm2snipe-linux-amd64 -o axm2snipe
chmod +x axm2snipeOr install with Go:
go install github.com/CampusTech/axm2snipe@latestOr build from source:
git clone https://github.com/CampusTech/axm2snipe.git
cd axm2snipe
go build -o axm2snipe .Copy the example config and fill in your values:
cp settings.example.yaml settings.yamlSee settings.example.yaml for all options and documentation.
# Test connections to ABM and Snipe-IT
axm2snipe test
# Download ABM data to local cache
axm2snipe download -v
# Dry run sync (no changes made - writes blocked at HTTP level)
axm2snipe sync --dry-run -v
# Full sync
axm2snipe sync -v
# Sync from cached data (avoids ABM API calls)
axm2snipe sync --use-cache -v
# Sync a single device by serial number
axm2snipe sync --serial ABCD1234XYZ -v
# Force update all assets (ignore timestamps)
axm2snipe sync --force -v
# Auto-create AXM custom fields in Snipe-IT and save mappings to config
axm2snipe setup -v
# Debug logging
axm2snipe sync -d
# JSON-formatted logs (useful for log aggregators like Splunk or Datadog)
axm2snipe sync -v --log-format json
# Write logs to a file in addition to stderr
axm2snipe sync -v --log-file /var/log/axm2snipe.log
# JSON logs to file
axm2snipe sync -v --log-format json --log-file /var/log/axm2snipe.log
# Print an ABM access token (useful for manual API testing with curl)
axm2snipe access-token
# Make an authenticated ABM API request
axm2snipe request https://mdmenrollment.apple.com/server/devices| Command | Description |
|---|---|
sync |
Sync ABM/ASM devices into Snipe-IT |
download |
Download ABM/ASM data to local cache |
setup |
Create AXM custom fields in Snipe-IT and save mappings to config |
test |
Test connections to ABM/ASM and Snipe-IT |
access-token |
Print an ABM API access token |
request <url> |
Make an authenticated ABM API GET request |
| Flag | Description |
|---|---|
--config |
Path to config file (default: settings.yaml) |
-v, --verbose |
Verbose output (INFO level) |
-d, --debug |
Debug output (DEBUG level) |
--log-file |
Append log output to this file (in addition to stderr) |
--log-format |
Log format: text (default) or json |
--version |
Show version and exit |
| Flag | Description |
|---|---|
--dry-run |
Simulate sync without making changes |
--force |
Ignore timestamps, always update |
--serial |
Sync a single device by serial number (implies --force) |
--use-cache |
Use cached data instead of fetching from ABM API |
--update-only |
Only update existing assets, never create new ones |
--cache-dir |
Directory for cached API responses (default: .cache) |
| Key | Description |
|---|---|
sync.dry_run |
Same as --dry-run flag |
sync.force |
Same as --force flag |
sync.rate_limit |
Enable rate limiting for API calls |
sync.update_only |
Only update existing assets, never create new assets/models/suppliers |
sync.mdm_only |
Only sync devices that are assigned to an MDM server |
sync.mdm_only_cache |
Also exclude non-MDM devices from the download cache (requires mdm_only) |
sync.product_families |
Filter devices by product family (Mac, iPhone, iPad, Watch, Vision) |
sync.use_cache |
Same as --use-cache flag |
sync.set_name |
Set asset name to "Model (Color)" on create |
sync.model_images |
Fetch device images from appledb.dev for newly created models (default: false) |
sync.supplier_mapping |
Map ABM/ASM purchase source IDs/types to Snipe-IT supplier IDs |
sync.field_mapping |
Map Snipe-IT fields to ABM/AppleCare source values |
snipe_it.computer_category_id |
Category ID for Mac models (overrides category_id for Macs) |
snipe_it.mobile_category_id |
Category ID for iPhone/iPad/Watch/Vision models |
snipe_it.custom_fieldset_id |
Fieldset ID to attach to auto-created models |
slack.enabled |
Enable Slack webhook notifications |
slack.webhook_url |
Slack incoming webhook URL |
- Connects to Apple Business Manager / Apple School Manager and Snipe-IT APIs
- Fetches all Snipe-IT models and suppliers to build local caches
- Retrieves all devices from ABM/ASM (with optional product family filter)
- For each device:
- Looks up the asset in Snipe-IT by serial number
- If not found and
update_onlyis true: skips - If not found: creates a new asset (after resolving model and supplier)
- Resolves model by matching ProductType (
Mac16,10), then DeviceModel (Mac mini (2024)), then PartNumber (MW0Y3LL/A) against Snipe-IT model numbers and names - If found: updates the asset with mapped fields (if ABM data is newer or
--force) - If multiple matches: skips with a warning
- Fetches AppleCare coverage details from ABM/ASM
- Resolves supplier from ABM/ASM purchase source (auto-creates if needed)
All field mappings are configured in settings.yaml under sync.field_mapping. The left side is the Snipe-IT field name (custom fields use the _snipeit_* DB column name), the right side is the ABM/AppleCare source value.
ABM device attributes:
| Source value | Description |
|---|---|
serial_number |
Device serial number |
device_model |
Marketing name (e.g. "Mac mini (2024)") |
color |
Device color (auto title-cased: SILVER -> Silver) |
device_capacity |
Storage capacity (e.g. "256GB") |
part_number |
Apple part number (e.g. "MW0Y3LL/A") |
product_family |
Product family (Mac, iPhone, iPad, etc.) |
product_type |
Hardware model identifier (e.g. "Mac16,10") -- used first for model matching |
order_number |
Order number (CDW-style orders auto-cleaned) |
order_date |
Order date (formatted YYYY-MM-DD) |
purchase_source |
Purchase source name |
status |
ABM device status |
imei |
IMEI number(s) |
meid |
MEID number(s) |
wifi_mac |
Wi-Fi MAC address, auto-formatted with colons |
bluetooth_mac |
Bluetooth MAC address, auto-formatted with colons |
ethernet_mac |
Ethernet MAC address(es), auto-formatted with colons |
eid |
eSIM EID |
added_to_org |
Date added to organization |
released_from_org |
Date released from organization |
assigned_server |
Assigned MDM server name |
AppleCare coverage:
| Source value | Description |
|---|---|
applecare_status |
Coverage status (auto title-cased: Active, Inactive, Expired) |
applecare_agreement |
Agreement/contract number |
applecare_description |
Coverage description |
applecare_start |
Coverage start date |
applecare_end |
Coverage end date |
applecare_renewable |
Whether coverage is renewable (true/false) |
applecare_payment_type |
Payment type (auto title-cased: Paid Up Front, Subscription, Abe Subscription, None) |
Standard Snipe-IT fields (use as the left side of field_mapping):
| Field | Description |
|---|---|
purchase_date |
Asset purchase date |
order_number |
Purchase order number |
warranty_months |
Auto-calculated from purchase date to AppleCare end date (not configurable) |
Example field mapping:
sync:
field_mapping:
# ABM device attributes -> Snipe-IT custom fields
_snipeit_mac_address_1: wifi_mac
_snipeit_storage_3: device_capacity
_snipeit_color_7: color
purchase_date: order_date
order_number: order_number
# AppleCare coverage -> Snipe-IT custom fields
_snipeit_warranty_end_date_4: applecare_end
_snipeit_warranty_id_5: applecare_agreement
_snipeit_applecare_status_9: applecare_status
_snipeit_applecare_description_10: applecare_description
_snipeit_applecare_start_date_11: applecare_start
_snipeit_applecare_renewable_12: applecare_renewable
_snipeit_applecare_payment_type_13: applecare_payment_type
_snipeit_assigned_mdm_server_14: assigned_serverUse the setup command to automatically create custom fields in Snipe-IT:
axm2snipe setup -vThis will:
- Connect to ABM/ASM to fetch MDM server names (used as listbox options) and all purchase sources
- Create AXM custom fields in Snipe-IT
- Associate them with your configured fieldset (
snipe_it.custom_fieldset_id) - Save the resulting field mappings to your config file under
sync.field_mapping - Scaffold
sync.supplier_mappingentries for every purchase source found (excludingMANUALLY_ADDEDsources, which require manual mapping), with TODO comments to fill in Snipe-IT supplier IDs
Alternatively, create them manually:
- Create custom fields under Admin > Custom Fields
- Note the DB column name for each field (e.g.
_snipeit_applecare_status_9) - Create a Custom Fieldset grouping these fields
- Assign the fieldset to your asset models
- Set
custom_fieldset_idin your config so new models get the fieldset automatically - Add entries to
field_mappingusing the DB column names as keys
| Field | Element | Format | Values |
|---|---|---|---|
| Wi-Fi MAC Address | text | MAC | -- |
| Bluetooth MAC Address | text | MAC | -- |
| Ethernet MAC Address | text | ANY | -- (may be comma-separated if multiple) |
| Color | text | ANY | -- |
| Storage | text | ANY | -- |
| Warranty End Date | text | DATE | -- |
| AppleCare Status | radio | ANY | Active, Inactive, Expired |
| AppleCare Start Date | text | DATE | -- |
| AppleCare Renewable | listbox | BOOLEAN | true, false |
| AppleCare Payment Type | radio | ANY | Paid Up Front, Subscription, Abe Subscription, None |
| Assigned MDM Server | text | ANY | -- |
axm2snipe can send a Slack notification whenever a new device is created in Snipe-IT. Messages use Slack Block Kit with device details, AppleCare status, MDM server, and a link to the asset in Snipe-IT.
To enable, create an incoming webhook and add to your config:
slack:
enabled: true
webhook_url: "https://hooks.slack.com/services/T.../B.../..."