EDIDC, EDID4, EDIDS: SAP IDoc Tables and Status Codes
Aug 24, 2026
Aug 24, 2026
Convert a purchase order to Excel, CSV, or JSON
Submit your purchase orders
Drop documents here, or click to file
Up to 50 files per batch
Uploading...
An SAP IDoc is stored across three tables: EDIDC holds one control record per IDoc with its current status, EDID4 holds the data records (the segment contents), and EDIDS holds the full status history. The status number tells you where the IDoc stopped: 51 means the application document did not post, 64 means it is waiting to be passed to the application, 68 means somebody closed it manually, and 03 or 53 mean it finished.
Last updated August 2026
If you support inbound purchase orders in SAP, you spend more time in these three tables and in the status list than in any transaction screen. This page is the reference: what each table actually stores, what each status number actually means, which program moves an IDoc out of which status, and the two or three traps that make an IDoc look fine when it is not.
Three tables, split by what they describe. The control record says who sent what and where it stands now, the data records carry the business content, and the status records carry the history of every step it went through.
| Object | What it holds | Rows per IDoc |
|---|---|---|
| EDIDC | Control record: sender, receiver, direction, message type, basic type, and the current status | Exactly 1 |
| EDID4 | Data records: one row per segment, with the segment content packed into SDATA | 1 per segment |
| EDIDS | Status records: the full status history, including the message class and number behind each error text | 1 per status change |
| EDI40 | Not a separate object. The table cluster EDID4 physically lives in at database level | n/a |
| EDIDD | Not a database table at all. The ABAP structure for a data record, used in function module interfaces | n/a |
The last two rows are where most confusion starts, so they are worth separating properly below.
One row per IDoc, keyed by DOCNUM. This is the table you filter when you want to find IDocs, and the STATUS column here is the current state, not the history.
| Field | Meaning |
|---|---|
| DOCNUM | IDoc number. The key that ties all three tables together |
| STATUS | Current status number, for example 51 or 53 |
| DIRECT | Direction. 1 = outbound, 2 = inbound |
| MESTYP | Message type, for example ORDERS for a purchase order |
| IDOCTP | Basic type, for example ORDERS05 |
| CIMTYP | Extension type, if the basic type was extended |
| SNDPRN / SNDPRT | Sender partner number and partner type |
| RCVPRN / RCVPRT | Receiver partner number and partner type |
| CREDAT / CRETIM | Creation date and time |
A point that costs people time: DIRECT matters more than it looks. The same status number means different things depending on direction, and the status ranges do not overlap by accident. Outbound statuses run in the 01 to 42 band, inbound statuses in the 50 to 75 band. If you are reading a status number and it does not make sense, check DIRECT first.
EDID4 holds one row per segment. The useful columns are DOCNUM, SEGNUM (the segment counter), SEGNAM (the segment name, for example E1EDKA1 or E1EDP01), PSGNUM (the parent segment number) and HLEVEL (the hierarchy level, which is how the flat rows reconstruct into a tree).
Then there is SDATA, and this is the part that surprises people the first time. SDATA is a single character field of 1000 characters holding the whole segment as one packed string. The individual fields of E1EDP01 are not separate columns. They are fixed-width slices of that one string. To read a quantity out of SDATA you have to overlay the segment structure onto it, which in ABAP means moving SDATA into a variable typed as the segment:
DATA: ls_edid4 TYPE edid4,
ls_e1edp01 TYPE e1edp01.
SELECT * FROM edid4 INTO ls_edid4
WHERE docnum = lv_docnum
AND segnam = 'E1EDP01'.
ls_e1edp01 = ls_edid4-sdata. " structure overlay
WRITE: / ls_e1edp01-menge, ls_e1edp01-menee.
ENDSELECT.This is also the reason an external reporting tool pointed at EDID4 gives you rows of unreadable text. The tool sees the cluster EDI40 and a 1000 character blob, and it has no idea that characters 63 to 77 are a quantity. Segment content is readable through WE02, WE09, or an ABAP overlay, and not really through generic SQL.
EDIDS is the table people skip and then wish they had not. EDIDC tells you the IDoc is at 51. EDIDS tells you why, because it stores every status the IDoc passed through along with the message that produced it.
| Field | Meaning |
|---|---|
| DOCNUM | IDoc number |
| COUNTR | Sequence counter of the status record |
| STATUS | The status number set at this step |
| LOGDAT / LOGTIM | When the status was set |
| STAMID / STAMNO | Message class and message number. This is the actual application error |
| STATXT | The rendered message text |
| STAPA1 to STAPA4 | The message parameters, for example the material number that could not be found |
STAMID and STAMNO are the fields worth knowing. A status 51 is not an error in itself, it is a container for one. The real error is an application message such as a missing material or a partner that does not resolve to a vendor master, and those two fields identify it exactly. Read the status record text before you touch anything, because it almost always names the missing object.
They describe the same data at three different levels, and only one of them is a table you query.
| Name | What it actually is | Use it for |
|---|---|---|
| EDID4 | The transparent-looking data record table from release 4.0 onwards | This is what you SELECT from |
| EDI40 | The table cluster EDID4 is physically stored in | Nothing, in day to day work. It is why native SQL tools behave oddly |
| EDIDD | An ABAP dictionary structure, not a database table | Typing internal tables in function module calls such as IDOC_INBOUND_WRITE_TO_DB |
If a code sample or a forum answer tells you to select from EDIDD, it is wrong or it predates 4.0. Select from EDID4.
The full list is maintained in WE47, and your system can carry custom entries. These are the standard ones you meet in purchase order processing.
Outbound statuses
| Status | Meaning | What it tells you |
|---|---|---|
| 01 | IDoc generated | Created, nothing sent yet |
| 02 | Error passing data to port | Port or file system problem, not a data problem |
| 03 | Data passed to port OK | Handed off. See the warning below about what this does not mean |
| 04 | Error in control information of EDI subsystem | The subsystem rejected it |
| 05 | Error during translation | The translator could not map it |
| 12 | Dispatch OK | The subsystem confirmed dispatch |
| 26 | Error during syntax check of IDoc (outbound) | The IDoc does not match its own type definition |
| 29 | Error in ALE service | Distribution model or partner profile problem |
| 30 | IDoc ready for dispatch (ALE service) | Generated and waiting. Nothing has left the system |
| 31 | Error, no further processing | Manually closed |
| 32 | IDoc was edited | A copy was changed by hand |
Inbound statuses
| Status | Meaning | What it tells you |
|---|---|---|
| 50 | IDoc added | Received and stored |
| 51 | Application document not posted | Reached the application and the posting failed. Retryable |
| 52 | Application document not fully posted | Partial post, usually a warning |
| 53 | Application document posted | Success. The purchase order or sales order exists |
| 56 | IDoc with errors added | Failed before the application, usually partner profile or syntax |
| 60 | Error during syntax check of IDoc (inbound) | Structure does not match the type |
| 61 | Processing despite syntax error | Forced through |
| 62 | IDoc passed to application | In flight |
| 63 | Error passing IDoc to application | The inbound function module could not be called |
| 64 | IDoc ready to be transferred to application | Waiting. Nothing has been attempted yet |
| 65 | Error in ALE service | Partner profile or inbound process code problem |
| 68 | Error, no further processing | Manually closed. Nothing was fixed |
| 69 | IDoc was edited | Changed by hand |
| 70 | Original of an IDoc which was edited | The pre-edit copy, kept for audit |
| 73 | IDoc archived | Moved out of the live tables |
Status 51 means the IDoc arrived intact, was passed to the application, and the application refused to post the document. The IDoc itself is fine. Something the IDoc referred to is not: a material that is not in the material master, a vendor that exists in one company code but not the one being posted to, a unit of measure the material is not maintained in, or a price condition that cannot be determined. Read STATXT on the status record, fix the master data, then reprocess. The IDoc does not need to be re-sent by the partner because the data records are already in EDID4.
Status 64 means the IDoc is stored, valid, and queued to be handed to the application, but that handover has not happened yet. Nothing has failed. It is a waiting state, which is exactly why it is so often misread as a failure. An IDoc sitting at 64 for two minutes is normal. One sitting at 64 since last Thursday is not.
This is the most common inbound complaint, and it has two distinct causes that need opposite fixes. Check the inbound parameters in WE20 for that partner and message type first, because the answer depends on which processing option is set.
| WE20 setting | Why it stalls at 64 | Fix |
|---|---|---|
| Trigger by background program | RBDAPP01 is what moves these IDocs. If nobody scheduled it, they queue forever | Schedule RBDAPP01 in SM37 with a variant that covers this message type |
| Trigger immediately | SAP tried to post it in a dialog work process and none was free at that moment | See below. The fix is counterintuitive |
The second case is the one that wastes days. Trigger immediately is not a guarantee. It asks for a dialog work process, and if the system is busy, or the partner sent a few thousand orders in one burst, there is no process available and the IDoc is simply left at 64. It does not retry on its own. SAP documents this behavior for immediate-processing IDocs in KB 1872637.
The fix at volume is to stop asking for immediate processing. Switch the partner to collect mode and schedule RBDAPP01 on a short cycle, every five or ten minutes. You give up a little latency and you get a queue that drains reliably instead of one that silently stops under load. If you would rather keep immediate processing, you need enough dialog work processes to absorb the peak, which is a Basis conversation and not a configuration toggle.
Status 51 is an error the system will let you retry. Status 68 is a decision a person made to stop retrying. Setting an IDoc to 68 does not fix, post, or cancel anything. It takes the IDoc out of the pool that RBDMANI2 and the error monitoring jobs pick up, so it stops appearing on the failure list.
That makes 68 useful and dangerous in the same breath. It is the right status when you have posted the document manually and the IDoc is now a duplicate you do not want reprocessed. It is the wrong status when it is used to make a monitoring report look clean, because the order it represents may never have been entered at all. If you inherit a system with a large 68 population, treat it as an unknown, not as resolved work.
Status 30 means an outbound IDoc was generated correctly and is waiting to be dispatched. It has not gone anywhere. Almost always the partner profile in WE20 has collect mode selected rather than transfer IDoc immediately, which is a deliberate setting for batching, not a fault. Run RSEOUT00, or WE14 interactively, and the status moves to 03.
The failure mode is the same shape as the inbound one: if collect mode is set and RSEOUT00 is not scheduled, outbound orders accumulate at 30 and nobody is told. Both directions depend on a background job that fails quietly when it is missing.
BD87 is the monitor most people use, and it will call the right program for you. It helps to know what it is calling, because at volume you schedule the program directly rather than clicking through the tree.
| Program | Transaction | Acts on | Moves it to |
|---|---|---|---|
| RSEOUT00 | WE14 | Outbound IDocs at status 30 | 03 |
| RBDAPP01 | BD20 for a single IDoc | Inbound IDocs at status 64 | 53, or 51 if the posting fails |
| RBDMANI2 | via BD87 | Inbound IDocs in error, mainly 51, also 63 and 65 | 53, or back to 51 |
| RBDAGAIN | via BD87 | Outbound IDocs in error | Depends on the error |
| RC1_IDOC_SET_STATUS | via SE38 | Mass status change, for example bulk 51 to 68 | The status you specify |
The order of operations that avoids repeat work: read STATXT in EDIDS, fix the master data or configuration it names, then reprocess with RBDMANI2. Reprocessing before the fix just produces a second status 51 record and makes the history harder to read.
WE05 with a status filter is the interactive route. For a scheduled check or a report, the join is straightforward as long as you take the current status from EDIDC and the error text from EDIDS.
SELECT c~docnum, c~mestyp, c~idoctp, c~sndprn,
c~status, c~credat,
s~stamid, s~stamno, s~statxt
FROM edidc AS c
INNER JOIN edids AS s
ON s~docnum = c~docnum
WHERE c~mestyp = 'ORDERS'
AND c~direct = '2' " inbound
AND c~status IN ('51','64','56','63','65')
AND s~status = c~status " the record for the current status
INTO TABLE @DATA(lt_failed).Without that last condition you get every historical status record for every IDoc, which is how a simple failure report turns into thousands of rows. If you want the ORDERS backlog by partner and age rather than a flat list, group on SNDPRN and CREDAT and alert on anything older than your processing window. Teams that already run scheduled checks over warehouse tables tend to treat this as one more freshness rule, and the same instinct applies here: the number that matters is not how many IDocs failed today, it is how long the oldest untouched one has been sitting there. For regulated buyers who have to evidence that inbound orders are processed under control, that status history in EDIDS is the audit trail, and it is worth mapping it to the control you are actually being asked to prove rather than rebuilding the evidence at audit time.
No, and this is the single most expensive misreading in the area. Status 03 means SAP passed the data to the port successfully. It says nothing about whether the EDI subsystem translated it, whether the VAN accepted it, or whether the partner ever saw it. Status 12, dispatch OK, is a stronger signal because the subsystem confirmed it, but the confirmation still stops at the subsystem.
There is a second place this hides. An outbound IDoc that reached 03 can still be stuck in the tRFC queue, and the queue is in SM58, not in any IDoc transaction. If a partner insists an order never arrived and the IDoc reads 03, check SM58 before you check anything else. The same trap exists on the message side of purchase order output, where a processed status means SAP handed the message off and nothing more, which is covered in SAP purchase order output determination.
| Transaction | What it does |
|---|---|
| WE02 / WE05 | IDoc list. Filter by date, direction, message type, partner, status |
| WE09 | Search IDocs by segment field content. The one people forget, and the fastest way to find an IDoc by PO number |
| WE19 | Test tool. Copy an existing IDoc, edit the data, and run inbound processing in debug |
| WE20 | Partner profiles. Where the processing option that causes status 64 and status 30 lives |
| WE21 | Port definitions |
| WE30 / WE31 | IDoc type and segment editor |
| WE47 | Status code maintenance, including custom statuses |
| WE60 | IDoc documentation, the readable segment and field reference |
| BD87 | Status monitor. Reprocess from here |
| SM58 | tRFC queue. Where a status 03 IDoc can still be stranded |
| SM37 | Job overview. Where you confirm RBDAPP01 and RSEOUT00 actually run |
WE09 deserves the callout. When a buyer calls about one purchase order and all you have is their PO number, WE09 finds the IDoc by searching segment content directly, which beats paging through WE02 by date.
Everything above assumes the order arrived as an IDoc. A large share of purchase orders do not. They arrive as a PDF attached to an email from a customer who is not on EDI, has no plans to be, and represents real revenue anyway. Those orders bypass EDIDC entirely and land on somebody who retypes them into ME21N or into the sales order screen.
That is the gap this tool fills. Upload the PDF or scanned purchase order and it returns the PO number, buyer, ship-to, dates, terms and every line item with quantity and unit price as Excel, CSV, JSON or an API response, in the same structured shape your IDoc segments would have carried. It is not an IDoc generator and it does not write to EDID4. It produces clean field-level order data so the manual path stops being a manual path. For the load routes into SAP itself see purchase order to SAP, and for how the ORDERS message type and ORDERS05 basic type are structured see IDoc purchase order in SAP.
For the purchasing document tables behind the order itself, see EKKO and EKPO purchase order tables and purchase order history in SAP. Document status, which is a different thing from IDoc status and a different thing again from message status, is covered in the SAP purchase order status table. If your inbound orders arrive as X12 rather than IDocs, the EDI 850 purchase order covers the segment layout.
Stop retyping purchase orders
Upload a PDF, scan, or photo of any PO and get clean Excel, CSV, or JSON line items in seconds.
Try it free25 pages free. No credit card required.