← Blog | Guides & Checklists

SCRA Batch File Format: DMDC Multiple Record Requests

November 6, 2026 · Mario Bailey
Share

The Department of Defense’s SCRA website can check up to 250,000 people in one upload. DMDC calls it a multiple record request. The catch is the file: it must be a fixed-width text file with every field in an exact character position, and a file that fails validation is rejected at upload and not processed at all.

This guide gives the complete layout for both the request file you upload and the result file you get back, taken from DMDC’s SCRA User Guide (version 5.29, updated May 27, 2026), plus Python you can use to build and parse the files. For single searches, see How to Run an SCRA Search.


File Rules

Before the layout, the rules every request file must follow:

  • Fixed width. Each field occupies a set range of character positions. No delimiters: not CSV, not tab-separated, not Excel.
  • Plain .txt, UTF-8 encoded. One record per line.
  • Allowed characters: numbers, letters, and spaces. Name fields cannot contain numbers but can include dashes and apostrophes. The customer record ID can also include dashes and apostrophes. Anything else produces an “Error Uploading File” message.
  • Up to 250,000 records per file. DMDC notes the maximum is shown on the upload screen and may change for performance reasons.
  • File name: letters, numbers, and underscores only. No spaces, no extra periods before the extension, at most 30 characters before .txt.

Request File Layout

Every field is left-justified and padded with spaces to its full length. Each record is 119 characters.

PositionsLengthFieldType and format
1-99Social Security NumberNumeric, no dashes or spaces, leading zeros kept
10-178Date of BirthNumeric, YYYYMMDD, or 8 spaces if not used
18-4326Last NameLetters, dash, apostrophe; no suffixes (Jr., Sr., III)
44-6320First NameLetters, dash, apostrophe
64-9128Customer Record IDLetters, numbers, dash, apostrophe; optional
92-998Active Duty Status DateNumeric, YYYYMMDD
100-11920Middle NameLetters, dash, apostrophe

What drives the match

DMDC: “While every field must be accounted for, the three fields that are most important for validating a match are” the SSN, last name, and active duty status date. Every field must be present in position, even if it is blank, so a missing value is written as spaces, never skipped.

The sample file in DMDC’s guide includes a record with no SSN, matched on date of birth and last name instead. As with single searches, the more identifiers you provide, the less likely a record comes back as a multiple match.

Choosing the active duty status date

The status date is the date DMDC reports status for, and it can differ for every record in the file. DMDC suggests “the loan origination, foreclosure, etc.” It must be on or after 19850930 and cannot be in the future (today plus one day counts as future).

One file can mix purposes: origination dates for a rate cap review on some records, planned sale dates for foreclosure holds on others. The customer record ID is how you tie each result back to the account it belongs to.


Uploading and Downloading

  1. Log in at scra.dmdc.osd.mil and open Multiple Record Request.
  2. Choose your file. It is validated immediately; a file that fails validation is not processed.
  3. Decide whether you need certificates. The default is No. If you choose Yes, pick the population: people on active duty, people not on active duty, or both.
  4. Accept the terms of use and upload.
  5. Return in about 24 hours. Results and certificates may not finish at the same time.
  6. Download the result file, and the certificate file as ZIP or PDF if you requested one.

Download promptly. Files expire 15 days after upload, and the file’s history disappears 30 days after download. Accounts are also terminated after 35 days without a login, taking access to uploaded files with them. See SCRA Website Login Problems.

The result file name carries the SCRA version as a prefix, for example scra4_0_myfilename.txt, so you can tell which version of the system processed it.


Result File Layout

Each result record is 184 characters. It echoes your request data and adds the match results. Note that it is not your request record with results appended: position 100 is blank, and the middle name moves from positions 100-119 in the request to 150-169 in the result. Parsers that assume the request layout carries through will read the wrong data.

PositionsLengthField
1-99SSN
10-178Date of Birth
18-4326Last Name
44-6320First Name
64-9128Customer Record ID
92-998Active Duty Status Date
1001Blank
1011On Active Duty on the Active Duty Status Date
1021Left Active Duty Within 367 Days of the Active Duty Status Date
1031Notified of Future Call-Up on the Active Duty Status Date
104-1118Active Duty End Date
1121Match Result Code (no longer used; always 0)
1131Error
114-1218Date of Match
122-1298Active Duty Begin Date
130-1378EID Begin Date
138-1458EID End Date
146-1472Service Component
148-1492EID Service Component
150-16920Middle Name
170-18415Certificate ID

All dates are YYYYMMDD. An empty active duty end date is returned as 00000000.


Reading the Status Codes

Position 101: On active duty on the status date

CodeMeaning
XYes, on active duty on the status date, and still on active duty
YYes, on active duty on the status date, and that period has since ended
NNo, not on active duty on the status date (check position 102)
ZData input issue (check the error code)

Position 102: Left active duty within 367 days (only applies when position 101 is N)

CodeMeaning
YLeft active duty within the 367 days before the status date
NDid not
ZNot applicable, or a data input issue

Position 103: Notified of a future call-up

CodeMeaning
YThe status date falls within the member’s notification period to report for active duty
NIt does not
ZNot applicable, or a data input issue

Ignore position 112. DMDC: the match result code “is no longer in use. All result files will return a ‘0’ value in the 112th position of each record, regardless of match parameters.” Status comes from positions 101 through 111.

Position 114: Date of match is the date DMDC ran the match, the “as of” date for the result. DMDC’s guide puts it plainly: “The current active duty status of servicemembers can and does change daily, so it’s important to record when the SCRA match was completed.”

Error codes (position 113)

CodeMeaning
9No errors
1Missing required field
2Invalid SSN (must be 9 digits, no dashes or spaces, leading zeros kept)
3Invalid date (must be YYYYMMDD; status date on or after 19850930; no future dates)
4Multiple records found; DMDC cannot identify the individual
BInvalid date of birth
DInvalid first name
EInvalid customer ID
GInvalid middle name

Treat code 4 like a multiple-match certificate: it says nothing about the person’s status. Resubmit those records with more identifiers.

Service component codes (positions 146-147)

The first letter is the branch, the second the component.

CodeComponentCodeComponent
ARArmy Active DutyFRAir Force Active Duty
AVArmy ReserveFVAir Force Reserve
AGArmy National GuardFGAir National Guard
AJArmy CadetFJAir Force Cadet
AZArmy affiliateSRSpace Force Active Duty
NRNavy Active DutySVSpace Force Reserve
NVNavy ReserveSJSpace Force Cadet
NJNavy CadetSZSpace Force affiliate
MRMarine Corps Active DutyCRCoast Guard Active Duty
MVMarine Corps ReserveCVCoast Guard Reserve
MZMarine Corps affiliateCJCoast Guard Cadet
HRPublic Health ServiceCZCoast Guard affiliate
ORNOAA ActiveZZOther

Positions 148-149 use the same codes for the component that issued a call-up notice.


Python: Build a Request File and Parse Results

This builds request records to the layout above and parses result records by position. It strips characters DMDC rejects and name suffixes DMDC says to leave out, and it raises an error rather than silently truncating a value that does not fit.

import re

# Request file layout, DMDC SCRA User Guide v5.29, Figure 31.
REQUEST_FIELDS = [  # (name, length)
    ("ssn", 9),
    ("dob", 8),
    ("last_name", 26),
    ("first_name", 20),
    ("customer_record_id", 28),
    ("active_duty_status_date", 8),
    ("middle_name", 20),
]

NAME = re.compile(r"[^A-Za-z '\-]")
RECORD_ID = re.compile(r"[^A-Za-z0-9 '\-]")
SUFFIX = re.compile(r"[ ,]+(JR|SR|II|III|IV|V)\.?$", re.IGNORECASE)  # DMDC: no suffixes


def clean_name(value):
    return NAME.sub("", SUFFIX.sub("", value.strip())).strip()


def request_line(rec):
    """Build one 119-character fixed-width request record."""
    values = {
        "ssn": rec.get("ssn", "").replace("-", "").strip(),
        "dob": rec.get("dob", ""),  # YYYYMMDD, or "" for 8 blanks
        "last_name": clean_name(rec["last_name"]),
        "first_name": clean_name(rec.get("first_name", "")),
        "customer_record_id": RECORD_ID.sub("", rec.get("customer_record_id", "")),
        "active_duty_status_date": rec["active_duty_status_date"],  # YYYYMMDD
        "middle_name": clean_name(rec.get("middle_name", "")),
    }
    if values["ssn"] and not re.fullmatch(r"\d{9}", values["ssn"]):
        raise ValueError(f"SSN must be 9 digits: {rec.get('customer_record_id') or rec['last_name']}")
    for field in ("dob", "active_duty_status_date"):
        if values[field] and not re.fullmatch(r"\d{8}", values[field]):
            raise ValueError(f"{field} must be YYYYMMDD: {rec.get('customer_record_id') or rec['last_name']}")
    line = ""
    for name, length in REQUEST_FIELDS:
        value = values[name]
        if len(value) > length:
            raise ValueError(f"{name} longer than {length} characters: {value!r}")
        line += value.ljust(length)  # every field is left-justified, space-padded
    return line


def write_request_file(records, path):
    with open(path, "w", encoding="utf-8", newline="\n") as f:
        for rec in records:
            f.write(request_line(rec) + "\n")


# Result file layout, DMDC SCRA User Guide v5.29, Figure 36 (1-based positions).
RESULT_FIELDS = {
    "ssn": (1, 9),
    "dob": (10, 17),
    "last_name": (18, 43),
    "first_name": (44, 63),
    "customer_record_id": (64, 91),
    "active_duty_status_date": (92, 99),
    "on_active_duty": (101, 101),          # Y, X, N, Z
    "left_within_367_days": (102, 102),    # Y, N, Z
    "notified_of_call_up": (103, 103),     # Y, N, Z
    "active_duty_end_date": (104, 111),    # 00000000 if none
    "error": (113, 113),                   # 9 = no errors
    "date_of_match": (114, 121),
    "active_duty_begin_date": (122, 129),
    "eid_begin_date": (130, 137),
    "eid_end_date": (138, 145),
    "service_component": (146, 147),
    "eid_service_component": (148, 149),
    "middle_name": (150, 169),
    "certificate_id": (170, 184),
}


def parse_result_line(line):
    line = line.rstrip("\r\n").ljust(184)
    return {k: line[a - 1 : b].strip() for k, (a, b) in RESULT_FIELDS.items()}

Usage:

write_request_file(
    [
        {
            "ssn": "123456789",
            "dob": "19880210",
            "last_name": "Smith",
            "first_name": "Jonathan",
            "customer_record_id": "LN-000417",
            "active_duty_status_date": "20260115",
        },
        # No SSN: date of birth and last name instead.
        {"dob": "19620416", "last_name": "Doe", "first_name": "Susan",
         "customer_record_id": "LN-000418", "active_duty_status_date": "20261024"},
    ],
    "scra_batch_20261106.txt",
)

with open("scra4_0_scra_batch_20261106.txt", encoding="utf-8") as f:
    for result in map(parse_result_line, f):
        if result["error"] == "4":
            print("Multiple matches, resubmit with more identifiers:", result["customer_record_id"])
        elif result["on_active_duty"] in ("X", "Y") or result["left_within_367_days"] == "Y" \
                or result["notified_of_call_up"] == "Y":
            print("Review for SCRA protections:", result["customer_record_id"])

Before uploading a production file, check a few records by hand against the layout table. A single misplaced field shifts every field after it.


What the Result File Can Miss

The result file reports what DEERS holds. DMDC’s guide notes that before 2007 it only received active duty periods of more than 30 consecutive days, that “coverage under the SCRA is broader in some cases” than the file reports, and that amended orders extending active duty may not be reflected. Persons relying on the file “should check to make sure the orders on which SCRA protections are based have not been amended.” The DOJ and the CFPB made the same point in their December 2024 joint letter, noting that active duty periods of less than 30 days may not appear.

A servicemember’s own notice and orders outrank a batch result. For more on reading results, see SCRA Status Report Explained.


Running Batches Without the File Work

Every batch cycle repeats the same steps: export, format, validate, upload, wait a day, download before the 15-day expiry, match results back to accounts, file the certificates, and log what was decided.

Civrel runs DMDC verification from your own records, single and batch, on a schedule. Results and certificates are stored with each case, status changes trigger monitoring alerts, and every check lands in the audit trail.


Frequently Asked Questions

How many records can a DMDC SCRA batch file hold?

Up to 250,000 records per file. DMDC notes the limit is displayed on the upload screen and may change.

What format does the DMDC SCRA multiple record request use?

A fixed-width, UTF-8 .txt file. Each 119-character record holds SSN, date of birth, last name, first name, customer record ID, active duty status date, and middle name, each in a fixed position and left-justified.

Can I upload a CSV or Excel file to the SCRA website?

No. The request file must be fixed-width plain text. Convert spreadsheet data to the fixed-width layout first.

How long does a DMDC batch request take?

Plan on about 24 hours. Results and certificates may complete at different times.

What does error code 4 mean in an SCRA result file?

Multiple records matched and DMDC cannot identify the individual, so no status is released. Resubmit with more identifiers.

What is the difference between X and Y in position 101?

Both mean the person was on active duty on the status date. X means they are still on active duty; Y means that period of active duty has since ended.

Related training

See these topics covered in depth in our free SCRA training videos. Watch now →

Mario Bailey, Founder & CEO of Civrel

Mario Bailey · Founder & CEO, Civrel

Mario serves in the Air National Guard (Cyber Systems Operations) and spent ten years as a software engineer before founding Civrel. He has been on the receiving end of SCRA compliance: getting his own protections applied took longer than it should have, and he built Civrel so institutions can get it right.

LinkedIn | About Civrel →

Disclaimer: This content is provided for general informational purposes only and does not constitute legal advice. SCRA obligations depend on your institution's specific facts and on applicable federal and state law. Consult qualified counsel before acting on anything you read here.

Ready to automate your SCRA compliance?

See how civrel.io replaces manual processes with continuous, automated monitoring.