In a UML sequence diagram, draw a synchronous call with a solid line and filled arrowhead, an asynchronous call or signal with a solid line and open arrowhead, and a reply with a dashed line. An HTTP 202 Accepted response is still the dashed reply to the HTTP request; 202 says the requested processing is incomplete, not that the request itself had no response. In the worked job flow below, the client call finishes at 202, while a later event-bus-to-worker message starts the background work.
Scope and terms before drawing
OMG UML 2.5.1 defines a Message as communication between lifelines and gives it a messageSort. The relevant sorts are synchCall, asynchCall, asynchSignal, and reply. Section 17.4.4.1 maps them to the visible notation: asynchronous messages have open arrowheads, synchronous messages have filled arrowheads, and replies use dashed lines.
Those marks describe the interaction model at the diagram's chosen abstraction level. They do not, by themselves, specify HTTP, AMQP, a queue product, thread scheduling, delivery guarantees, persistence, or a timeout. A line labelled “publish” could be a synchronous broker API call; a separate broker-to-consumer line can be an asynchronous signal. The reviewer should be able to tell which statement each arrow makes.
Use these three questions before choosing an arrow:
| Question | UML message sort | Visible notation |
|---|---|---|
| Must the sender wait for the invoked operation to finish before this interaction continues? | synchCall | solid line, filled arrowhead |
| Does the sender hand off a call or signal without waiting for a result from that receiver? | asynchCall or asynchSignal | solid line, open arrowhead |
| Is this message returning from an earlier synchronous call? | reply | dashed line, open or filled arrowhead |
“Synchronous” is about the caller's wait relationship, not whether the whole business job completes. “Asynchronous” is about the modeled send, not a promise that the message is durable or delivered exactly once.
Worked example: accept an export job, then process it
The fictional system accepts a long-running export request. It has five lifelines: a client, a job API, a job store, an event bus, and an export worker. The example makes these assumptions explicit:
| Input or boundary | Assumption in this diagram |
|---|---|
| HTTP request | POST /exports remains open until the API returns one HTTP response |
| Acceptance point | the API returns 202 only after the job row exists and the broker acknowledges the publish |
| Job identifier | J42 identifies both the status resource and the requested export |
| Event identity | evt-7f remains stable if the same event is redelivered |
| Background result | the worker updates the job row; the client later polls the status resource |
| Delivery guarantee | deliberately unspecified; the sequence is not proof of durability or exactly-once handling |
RFC 9110 says 202 Accepted means the request was accepted for processing but processing is not complete, and that the response representation ought to describe current status and point to a status monitor. That is why this example replies with /jobs/J42. The status code changes the meaning of the response; it does not turn the HTTP response arrow into an asynchronous UML message.
Reproducible Schematex source
sequence "202 Accepted export job"
autonumber 1 1
actor Client
participant API as "Job API"
database Jobs as "Job Store"
queue Bus as "Event Bus"
participant Worker as "Export Worker"
Client ->+ API : POST /exports
API ->+ Jobs : create J42 [queued]
Jobs -->- API : committed
API ->+ Bus : publish ExportRequested(evt-7f, J42)
Bus -->- API : accepted evt-7f
API -->- Client : 202 Accepted + /jobs/J42
Bus ->>+ Worker : ExportRequested(evt-7f, J42)
Worker ->+ Jobs : set J42 [running]
Jobs -->- Worker : updated
Worker ->+ Jobs : set J42 [done, result URL]
Jobs -->- Worker : updated
deactivate Worker
Client ->+ API : GET /jobs/J42
API ->+ Jobs : read J42
Jobs -->- API : done + result URL
API -->- Client : 200 OK + result URL
Schematex 1.0.14 strictly parsed and rendered this source on September 6, 2026. Its current sequence syntax reference maps -> to a synchronous call, ->> to an asynchronous signal, and --> to a reply in native sequence syntax. The same page warns that Mermaid-compatible sequenceDiagram input uses different arrow-token meanings; do not copy a token between dialects without checking the header.
Read the sequence in three phases
1. Synchronous acceptance
Messages 1–6 form nested request-response work. The client waits for the API. The API waits for the job store to confirm the queued row, then waits for the event bus to accept the publish. Each filled call arrow has a corresponding dashed reply before its caller proceeds.
The API's 202 Accepted is message 6, a dashed reply. At that point the HTTP interaction ends. The reply reports an accepted job and gives the client a status resource; it does not claim that the export exists yet.
2. Asynchronous processing
Message 7 uses the open arrowhead. The event bus sends ExportRequested(evt-7f, J42) to the worker without a modeled return message. The worker then makes ordinary synchronous calls to the job store while changing the job status. A queue consumer can therefore receive asynchronously and still make synchronous calls inside its handling path.
CloudEvents 1.0.2 defines an event as a record of an occurrence and its context, separate from the message that transports it. It also requires producers to make source plus id unique for each distinct event and permits a redelivery to keep the same identity. The short evt-7f label is fictional, but it exposes the review question: can a consumer recognize the same event if delivery is retried? An ID enables duplicate recognition; it does not make the handler idempotent automatically.
3. Synchronous status read
Messages 12–15 are a new request-response exchange. The client asks for J42, the API reads the stored status, and the API returns 200 OK with the result URL. This polling interaction is synchronous even though it observes work that was performed asynchronously.
Checks and invariants
Use these checks before approving a sequence diagram that mixes calls and events:
- Every dashed reply points back toward the caller of a preceding synchronous call.
- The
202 Acceptedarrow is a reply, and its label names the status resource/jobs/J42. - The asynchronous
ExportRequestedarrow has no dashed reply from the worker to the event bus. - The same job identifier
J42appears in acceptance, processing, and status lookup. - The same event identifier
evt-7fappears at broker acceptance and consumer delivery. - Job status moves only forward in the happy path:
queued → running → done. - No arrow shape is treated as evidence of durable storage, retry policy, ordering, or exactly-once processing.
- The diagram's vertical order is consistent: the API returns
202only after the two acceptance replies shown above it.
For a negative test, change message 6 from API --> Client to API ->> Client. The new open solid arrow would assert an asynchronous message rather than the HTTP reply. The client call would then have no return message, contradicting the stated request-response boundary.
Failure modes the clean sequence does not solve
A 202 with no status contract. Returning 202 without a stable job identifier, current state, or monitor leaves the client unable to distinguish queued, failed, lost, and completed work.
A dashed line used for “async.” Some informal diagrams use dashes to mean delayed or background. In UML, the line style belongs to a reply. The arrowhead—not the dashed stroke—distinguishes an asynchronous message.
A queue icon treated as a guarantee. The event-bus lifeline says where the handoff occurs. It does not establish persistence, acknowledgement scope, retention, ordering, dead-letter handling, redelivery delay, or maximum attempts.
A dual-write gap hidden between rows. Creating J42 and publishing evt-7f are two state changes. If one succeeds and the other fails, the job can be stranded or duplicated. A real design needs a defined atomicity or reconciliation pattern, such as a transactional outbox, and a test for the failure between those two operations.
A duplicate event treated as a duplicate job. Redelivering evt-7f should not create a second logical export, but that depends on consumer state and idempotency rules. The diagram surfaces the identifier; implementation and verification remain separate work.
A happy path mistaken for an operational specification. Cancellation, authentication, authorization, timeouts, publish rejection, worker crashes, poison messages, result expiry, privacy, and observability are outside this one figure. Add guarded alt, break, or loop fragments only when the review needs those behaviors; do not hide them behind a generic “error” note.
Reproduce the distinction
Paste the source into the Schematex playground, render it, and inspect messages 6 and 7 side by side. Message 6 should be dashed because it returns from POST /exports; message 7 should be solid with an open arrowhead because it hands an event to the worker. Then challenge the design by adding a broker-rejection alt branch before 202 and a duplicate-delivery loop around the worker. Those additions test the architecture without changing what the three arrow styles mean.