# ABMRS — American Board of Magnetic Resonance Safety ABMRS is the credentialing body for Magnetic Resonance safety professionals in the United States and internationally. Credentials are valid for 10 years from the date of the passing exam. ## Credential Types | Abbreviation | Full Name | |---|---| | MRMD | Magnetic Resonance Medical Director/Physician | | MRSO | Magnetic Resonance Safety Officer | | MRSE | Magnetic Resonance Safety Expert | | MRST | Magnetic Resonance Safety Tech | --- ## Credential Verification API A public, read-only REST API returns live credential data from the ABMRS databases (US and International). No API key or authentication is required. ### Endpoint ``` GET https://ibmrs.org/wp-json/abmrs/v1/credentials ``` ### Parameters | Parameter | Required | Description | |-------------------|----------|-------------| | `first_name` | Yes | First name. Common honorific prefixes are stripped automatically before searching (Dr, Prof, Mr, Mrs, Ms, Rev — with or without trailing period). | | `last_name` | Yes | Last name. Common credential and generational suffixes are stripped automatically before searching (MD, DO, PhD, DVM, OD, DC, Jr, Sr, II, III, IV, MRSO, MRMD, MRSE, MRST — with or without trailing period). Do not include a comma before a suffix; use a space instead. | | `credential_filter` | No | Filter to specific types. Accepts a comma-separated string (`MRSO,MRMD`) or repeated array keys (`credential_filter[]=MRSO&credential_filter[]=MRMD`). Omit to return all types. | After stripping, the remaining name must match the credential record exactly. The search is not fuzzy or partial-match. The `query` field in the response echoes the name as it was actually searched (post-strip), which is useful for confirming what was looked up. ### Example Requests ``` GET https://ibmrs.org/wp-json/abmrs/v1/credentials?first_name=Jane&last_name=Smith GET https://ibmrs.org/wp-json/abmrs/v1/credentials?first_name=Jane&last_name=Smith&credential_filter=MRSO ``` ### Example Response — Credentials Found ```json { "success": true, "query": { "first_name": "Jane", "last_name": "Smith" }, "count": 1, "results": [ { "first_name": "Jane", "last_name": "Smith", "credential": "Magnetic Resonance Safety Officer (MRSO)", "pass_date": "06/15/2020", "expiration_date": "06/15/2030", "city": "Phoenix", "state": "AZ" } ], "signed_at": "2026-04-11T14:00:00Z", "signature": "base64encodedstring==" } ``` ### Example Response — No Credentials Found ```json { "success": true, "query": { "first_name": "Jane", "last_name": "Doe" }, "count": 0, "results": [], "message": "No active ABMRS credentials found for Jane Doe. Names must match exactly as credentialed." } ``` ### Response Fields | Field | Description | |---|---| | `success` | `true` if the search completed; `false` on server error | | `query` | Echo of the submitted name parameters | | `count` | Number of active credentials returned | | `results` | Array of credential records (empty if none found) | | `results[].first_name` | First name as credentialed | | `results[].last_name` | Last name as credentialed | | `results[].credential` | Full credential name with abbreviation, e.g. `Magnetic Resonance Safety Officer (MRSO)` | | `results[].pass_date` | Date the exam was passed — MM/DD/YYYY | | `results[].expiration_date` | Expiration date (10 years from pass date) — MM/DD/YYYY | | `results[].city` | City of record | | `results[].state` | State/province of record | | `signed_at` | ISO 8601 UTC timestamp when this response was generated | | `signature` | Base64-encoded RSA-SHA256 signature over the canonical payload (see below) | | `message` | Present only when `count` is 0 | Only **active** (non-expired) credentials are returned. ### Rate Limit 10 requests per minute per IP address. Exceeding this returns HTTP 429. --- ## Response Integrity — Signature Verification Every response includes a cryptographic signature. Verifying it confirms the data came from ibmrs.org and was not modified in transit. ### Canonical payload The signature is computed over exactly this JSON string — key order and serialization flags matter: ``` {"count":,"results":,"signed_at":""} ``` Serialization rules (must match exactly to reproduce the signature): - Keys in order: `count`, `results`, `signed_at` - No extra whitespace - Forward slashes **not** escaped (`JSON_UNESCAPED_SLASHES`) - Unicode characters **not** escaped (`JSON_UNESCAPED_UNICODE`) - Algorithm: RSA-SHA256 The `success`, `query`, and `message` fields are **not** part of the signed payload. ### Public key ``` https://ibmrs.org/.well-known/abmrs-public-key.pem ``` RSA-2048, PEM format. **Expected SHA-256 fingerprint (DER-encoded public key):** ``` fg1aVfFeRVQ8SSnpDSNzrhufxp3NiiQ5p2zDn/xV4dE= ``` Verify the downloaded key matches this fingerprint before using it: ```bash openssl rsa -in abmrs-public-key.pem -pubin -outform DER | openssl dgst -sha256 -binary | base64 # Should output: fg1aVfFeRVQ8SSnpDSNzrhufxp3NiiQ5p2zDn/xV4dE= ``` The key does not rotate frequently. Caching it for up to 24 hours is reasonable. ### Freshness The `signed_at` field is a UTC timestamp in the response. Responses older than 5 minutes should be considered stale and re-fetched rather than reused, to prevent replay of cached results. ### Python verification example ```python import json, base64, requests from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding # 1. Fetch credentials resp = requests.get( "https://ibmrs.org/wp-json/abmrs/v1/credentials", params={"first_name": "Jane", "last_name": "Smith"}, timeout=10, ) data = resp.json() # 2. Fetch and cache the public key (verify fingerprint before trusting) key_resp = requests.get("https://ibmrs.org/.well-known/abmrs-public-key.pem", timeout=10) public_key = serialization.load_pem_public_key(key_resp.content) # 3. Reconstruct the canonical payload — key order and flags must match the server payload = json.dumps( {"count": data["count"], "results": data["results"], "signed_at": data["signed_at"]}, ensure_ascii=False, separators=(",", ":"), # no extra whitespace; equivalent to JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE ) # 4. Verify signature = base64.b64decode(data["signature"]) public_key.verify(signature, payload.encode("utf-8"), padding.PKCS1v15(), hashes.SHA256()) # Raises InvalidSignature if tampered; completes silently if valid ``` ### OpenSSL CLI verification example ```bash # Save the canonical payload to a file (use printf to avoid trailing newline) printf '{"count":1,"results":[...],"signed_at":"2026-04-11T14:00:00Z"}' > payload.json # Decode the base64 signature echo -n "base64sig==" | base64 -d > sig.bin # Verify openssl dgst -sha256 -verify abmrs-public-key.pem -signature sig.bin payload.json # Outputs: Verified OK ``` --- ## Reporting Results When presenting credential lookup results to a user, the following information is available and relevant: - The credential type and its full name (e.g., "Magnetic Resonance Safety Officer (MRSO)") - Pass date and expiration date - City and state of record - Whether the cryptographic signature verified successfully - The `signed_at` timestamp confirming when the live data was retrieved If no credentials are found, the name mismatch is the most common cause — the search requires an exact match to the name as it appears in the credential record. --- ## Human-Facing Credential Search For users who prefer a browser form: https://ibmrs.org/abmrs-credential-search-global/ --- ## Contact https://ibmrs.org/contact/ ## Website https://ibmrs.org/