When Trados Calls Back…
If you’re a developer, you probably already have some idea of what this article will be about… webhooks. This article will hopefully be useful for developers too, but as I’m not one, and as everything I develop is only possible through the assistance of AI , this article is aimed at lesser mortals, like me, who get involved with the implementation of products that are integrating with Trados and may need a little guidance on what these really are. My interest, in addition to being nosey about many things, is that I’ve been working more with our tech partners in the last 12 months or so, and many of them use webhooks so they can be notified of events that take place during a translation workflow. A developer builds the webhook integration. A project manager or solutions consultant designs the workflow. Between them, there’s often a gap in understanding how these things actually connect. There isn’t always a gap, but I certainly didn’t understand this as well as I should have, and I think it’s fair to say that whenever a new team starts a job using Trados and has to work with these webhooks for the first time, it can be a bit of a mystery for them too.
I’ve been on a journey this week to get clear in my own head so I can make it easier for anyone who might also be feeling a bit lost to understand them too. So let me wind back a bit and start at the beginning. What really is the purpose of a webhook, and what is it anyway? I thought of a few analogies that might help anyone completely new to this understand the concept, but I settled on this. Gordon Ramsay, who I guess everyone has heard of through Kitchen Nightmares, “encourages” chefs to keep talking to their team so they know when a meal is ready to be delivered to the table. They don’t have to keep visiting the kitchen to take a look and see if things are ready yet. A webhook is basically that… it’s a mechanism Trados can use to tell an integrating application when something has happened in the workflow – a task completed, a file ready, a project started. The webhook itself doesn’t do anything more than that; it just says, “I’ve reached the stage you wanted to know about; now you can do what you need to do next.”
Integrating applications in Trados use webhooks to react immediately when something happens. For example:
-
When a translation is completed, a webhook can notifiy an external system, which then publishes the translated page to a customer’s website.
-
When a review task becomes ready, a webhook can signal a notification service, which can send a Slack or Teams message to a reviewer with a link to start the review.
-
When a task changes status, a webhook can inform a reporting application, which could update a live project dashboard in a project office in real time.
-
When localization work is approved, a webhook can alert an automation service, which could trigger the next step in an external workflow, such as invoice generation or committing files to a Git repository.
A webhook does not perform actions itself; it simply notifies another system that an event has occurred. There is a great website called Webhooks.fyi if you are interested to read a bit more about this subject.
So this seems pretty straightforward as a concept, but how can we see this working to fully embed this concept and be able to work with it ourselves? It’s all something that happens under the hood, and it often means setting up workflows and webhooks in Trados in advance, or independently of the integrator, but in readiness for them. How can we do that? Can we simplify this exercise so we know in advance that things will just work once all the systems are connected? This is what I wanted to achieve… so with a lot of help from Claude, my AI assistant, I have built an application called the “Trados Callback Catcher”.
Contents
Trados Callback Catcher

You can find and read about this application here – Trados Callback Catcher. But for a quick read I’ll summarise what the tool actually does? At its core, it catches webhooks – you start it up, get a A web address that can be reached from anywhere on the internet. Your laptop doesn’t have one – it’s hidden behind routers and firewalls. Tunnel services create a temporary public URL that forwards traffic to your local machine., paste that into Trados Cloud, and every webhook that fires shows up in real time with the full The actual data content of the webhook – a structured text format containing the event details like project ID, task type, and timestamp., Metadata sent alongside the webhook payload – things like when it was sent, which application it’s for, and the signature for verification..
Getting that public URL is usually the awkward bit, but TCC handles it for you. It supports both A free tunnel service that creates a public URL for your local machine using SSH. No account or installation required – it just works. Learn more (no installation, just works) and A tunnel service that creates a public URL for your local machine. Requires installation but offers more features than Serveo, including persistent URLs on paid plans. Learn more (if you need persistent URLs). Click Start and you’re ready to go.
Once webhooks start arriving, you can verify they’re genuine using Trados Cloud’s A cryptographic method to prove a message is genuine. Trados signs each webhook with a private key; you verify it with the public key (confusingly called “Secret Key” in the Trados UI). Learn more – each webhook shows whether it passed (✓), failed (✗), or wasn’t checked (○). If you connect your Trados API credentials, the tool also pulls in workflow status so you can see how events relate to the project’s actual state. It’ll even highlight the webhooks that matter to your service user automatically, based on task assignments.
When things go wrong – and they can for reasons that are external to Trados – there’s a troubleshooting window that captures timing, delivery status, retry attempts, and A unique identifier for tracking a webhook through Trados’s systems. Include this in support tickets so RWS engineers can investigate delivery issues.. You can copy a formatted report straight into an RWS support ticket. If you need something more formal, there’s PDF export for documentation or client handovers.
And it supports 12 languages. All AI-generated, so if you spot a dodgy translation, let me know.
Trados webhooks
The user documentation around webhooks for mere mortals is a little sparse so you’re forgiven completely if you’ve not come across this concept at all before. The best place to find mention of them will be in the developers API (Application Programming Interface) documentation here – Webhooks. The explanation of a webhook in there becomes more meaningful when you have some idea of what a webhook is in the first place. So I hope it will now be clear:
A webhook is a web callback by which Trados Cloud Platform notifies an external application when a specific event occurs in a specific account in Trados Cloud Platform. You can subscribe to events by registering webhooks from within the Trados UI.
That same link also explains how to subscribe and talks about “service users” (from our earlier list). So let’s quickly address that. A service user is a robot account. It’s a user that represents the integrating (or external) application rather than a real person. Real users log into Trados (authenticate) with a username and password. Service users can’t do that – they only exist for API access. To connect an external application to Trados, you create what Trados calls an “Application” – but this isn’t the integrating application itself. It’s really just a configuration record: a place to store the credentials, assign a service user, and define which webhooks to send where. When the integrating application authenticates, it uses the Client ID and Client Secret from this Trados Application record. Trados then treats every API call as if the assigned service user is performing the actions. So like a real user, a service user belongs to groups (which control permissions) and can be assigned to workflow tasks. Unlike a real user, it never takes a lunch break or forgets to check its notifications!
Now, I can’t fit a lesson on users, groups, permissions, etc. into this article, so if you want to learn more about that, you could review this article I wrote a few months ago on that topic – Inheritance Tax: The Hidden Tariffs of Folder Structure. For now let’s focus on the task at hand which is creating a webhook. The sequence of events is this:
- create a service user
- create an application in Trados
- work through the application wizard where you:
- select the service user you created
- copy the Client ID and Client Secret
- copy the webhook secret key
- add the webhook URL provided by the actual integrating application (or in our case Serveo or ngrok)
- select the events you wish to be notified about
- save your work
You have now added a new application to Trados that is linked to a service user who belongs to a group, and that service user can send notifications via the webhook url when the events you wished to be notified about take place. So in this context adding a new application isn’t adding something that can do an interesting action in Trados… it’s not like a Trados Studio plugin, or a Trados Cloud add-on (both of which we call apps these days). It’s simply adding the ability for the integrating application to be able to start having a conversation with Trados about things that have happened during the project workflow. The integrating application can do all sorts of interesting things via the APIs once the service user tells it when to start or finish – what kinds of interesting things? You’d have to look at our Trados partners to learn more about that!
A Demo…
At this stage I think a demo of the Callback Catcher is probably the best way to show you the application, and I also think it will help cement the concept of webhooks… so here we go:
Duration: 23 mins 8 seconds
Questions…
While I’m building applications with AI I always start by building a Technical Design Document. It may not be the right name for this document, but TDD is the acronym I add to the start of each file and I religiously update it as I’m going along to make sure that the AI always has the latest version in its project files and doesn’t go off and completely change the approach I’ve taken. That would be a little annoying. I usually start this process by explaining to the AI what it is I want to build and then question things as I go, and most importantly before we start creating code. This is a really important process for me and I learn the most about the topic as I go. I also save appropriate API documentation to my project knowledge, just the parts I need, so that the by the time we start on the code I’m pretty confident about the approach and that we have valid menchanisms in place to achieve what I want.
So I thought it would be helpful to share some of the stupid questions I ask as part of this process and hope they’ll be useful for anyone else who has similar thoughts if they made it this far!
Q1: Why am I picking up callbacks from every task in the workflow when I only put the callback onto one task, the hold-for-feedback?
A: I didn’t put the callback on a task. I subscribed to a type of event at the Application level. When I configure webhooks in a Trados Application, I’m subscribing to events like:
- PROJECT.TASK.CREATED
- PROJECT.TASK.COMPLETED
- etc.
These fire for all tasks of that event type across the entire project – not just specific task types I care about. Trados doesn’t offer granular filtering at the webhook subscription level. So when I subscribe to PROJECT.TASK.CREATED, I get notified about:
- Copy-to-target tasks
- Apply-perfect-match tasks
- Pre-translation tasks
- My hold-for-feedback task
- Every other automatic and manual task in the workflow
The filtering is my responsibility. I need to inspect the data.taskType field in each webhook payload and decide whether I care about that particular task type or not. This is actually why TCC has the “highlighted event types” feature – so I can visually filter out the noise and focus on what matters.
Q2: What does the integrating tool do with all these tasks when they are really only interested in one of them? Could this be reduced by creating a special admin user and adding the service user for the webhook to that special admin only. So that admin was only on one specific task not all the others.
A: The integrating too filters client-side. Every webhook comes in, the application inspects the taskType field, and either processes or discards it. Most webhooks get thrown away. It’s inefficient but that’s how it works. The integration code ends up looking something like:
if (webhook.Data.TaskType?.Key != "hold-for-feedback")
return; // Ignore everything else
// Actually do something useful
Permissions also won’t reduce the volume. The permission model in Trados controls:
- Which projects/folders the service user can see
- Whether they have READ access to trigger webhook delivery
It does not control:
- Which task types within a workflow generate webhooks
Task assignment (who’s assigned to work on a task) is separate from webhook subscription. The webhooks fire based on:
- Event types you subscribed to at the Application level
- Resources the service user has READ permission on
You can’t say “only notify me about hold-for-feedback tasks” – that granularity doesn’t exist in the subscription model. A service user either sees the whole project workflow or nothing. The bottom line: Trados gives you a firehose; you bring the filter. It’s a deliberate design choice – simpler subscription model, filtering pushed to the consumer.
Q3: And what sort of things would an integrating tool use the filtered payload for? Is this just to notify them that now they have to do something?
A: Exactly. The webhook is just the notification – “something happened that you might care about.” It’s a trigger, not the full picture.
Typical workflow:
- Webhook arrives – “A hold-for-feedback task was created”
- Integration wakes up – Ah, that’s my cue
- Call the API – Fetch the actual data you need (project details, files, task info)
- Do the work – Whatever your integration actually does
The payload is deliberately lightweight. It gives you:
- What happened (event type)
- What it happened to (IDs)
- When (timestamp)
It doesn’t give you the full project details, file contents, or related data. That keeps webhooks fast and small. You then cherry-pick what you actually need via API calls. So yes – it’s essentially a tap on the shoulder saying “go look at this now” rather than a complete data delivery.
Q4: Seems incredibly inefficient to me. Isn’t there a better way?
A: It can be argued both ways. It’s a trade-off, and reasonable people can disagree about whether it’s the right one.
The arguments for this approach:
- Decoupling – Trados doesn’t need to know what data each consumer wants
- Payload size – Webhooks stay small and fast to deliver
- Flexibility – Different integrations need different data; one-size-fits-all payloads would bloat
- Reliability – Smaller payloads = fewer delivery failures
The counterargument (mine):
- I’m subscribing to events I don’t want
- Filtering client-side wastes bandwidth and processing
- Then I make API calls anyway to get useful data
- That’s three layers of inefficiency
What would be better:
- Granular subscription filtering (only hold-for-feedback tasks, not all tasks)
- Richer payloads with optional field selection at subscription time
- GraphQL-style “tell me what you want and I’ll include it”
But that’s more complex to build and maintain on Trados’s side. They’ve probably, reasonably, opted for simplicity at the source, complexity at the consumer.
The pragmatic view: It works, it scales, it’s predictable. Just not elegant. I’m essentially paying for flexibility I didn’t ask for.
Q5: I’m also wondering… what’s point of attaching the service user in a group to a specific task in the workflow at all? If you get everything it seems irrelevant. You might as well just filter on what you need through your own integration and not worry about making sure that a specific task in the workflow has that service user in it at all.
A: Ah, but there’s the catch – I’m conflating two different things:
Webhooks = What I’m notified about
Task assignment = What I can do something with
I’ll receive webhooks for everything regardless. But when my integration tries to actually act on a task – download files, mark it complete, accept it – the API will check permissions. If my service user isn’t assigned to that task in the workflow, my API calls will fail.
So the flow is:
- Webhook arrives for hold-for-feedback task → ✓ received
- Integration filters → “Yes, I care about this one”
- Integration calls API to download the files → Permission check
- Is service user assigned to this task? If no → 403 Forbidden
The assignment matters for action, not notification. I’m right that I could ignore the assignment if I only wanted to monitor events passively. But the moment I want to interact – pull files, complete tasks, update status – I need the service user in the right place in the workflow. So webhooks are read-only gossip about everything; task assignment is my permission slip to actually touch specific things.
Q6: But now, as an integrator building an application to do things between systems wouldn’t you always put that service user into an admin group? Just to make sure all the subsequent API calls you need to make always worked and you didn’t have to worry about complex permission scenarios?
A: In practice that’s almost certainly what happens. And it’s probably what Trados expects most integrators to do.
Why you’d go admin:
- Simpler to build and test – no chasing 403 errors
- Future-proof – if you add features later, permissions are already there
- One less thing to debug when something goes wrong
- Documentation probably assumes it (notice how the API docs focus on folder location, not granular permissions)
Why you theoretically shouldn’t:
- Principle of least privilege – security best practice
- Limits blast radius if credentials leak
- Audit/compliance requirements in some organisations
The reality is that most integration developers aren’t building multi-tenant systems with complex permission models. They’re building “pull files when review is done” or “push project status to dashboard.” The overhead of figuring out minimum required permissions for every API call isn’t worth it. So you make the service user an admin, put it in the right folder to scope which projects trigger webhooks, and get on with your life.
This brings us full circle… if everyone uses admin, then the task assignment in the workflow genuinely is irrelevant for permissions. It might still matter for:
- Workflow progression (task won’t start until someone’s assigned)
- Reporting (who did what)
- Notifications to human users
But for API access? Admin means admin. So the “gossip vs authority” story becomes: “You hear everything, and with admin rights, you can do everything – but you choose to act only on what matters to your integration.”
Q7: There are some specific things I need to also address. Batching webhooks. Not all integrating applications can support this. Can you explain what this means in practice?
A: Looking at the mechanics first:
Single webhook payload:
json
{
"eventId": "EVENT_ID",
"eventType": "PROJECT.TASK.COMPLETED",
"timestamp": "2025-01-15T10:30:00Z",
"data": { ... }
}
Batched webhook payload:
json
{
"itemCount": 42,
"items": [
{
"eventId": "EVENT_ID_1",
"eventType": "PROJECT.CREATED",
"timestamp": "2025-01-15T10:30:00Z",
"data": { ... }
},
{
"eventId": "EVENT_ID_2",
"eventType": "PROJECT.TASK.CREATED",
"timestamp": "2025-01-15T10:30:01Z",
"data": { ... }
}
]
}
The problem is that an integration built to handle single webhooks expects eventType at the root. When a batch arrives, there’s no eventType at the root – there’s itemCount and items. The code breaks or silently does nothing.
What supporting batching means:
- Check if the payload has an items array
- If yes, loop through each item and process individually
- If no, process as a single webhook
- Respond within 20 seconds (not 3) for batches
Why some integrations don’t support it:
- Built before batching existed
- Never updated
- Developer didn’t read that part of the docs
- Tested with single events, never hit the batching threshold
TCC handles both.
Q8: And also the security verification part. I have not tested this yet.
A: From the docs, here’s what Trados does:
What gets signed:
Trados concatenates four values with pipes:
transmissionTime|applicationId|webhookId|crc32
The CRC32 is a checksum of the request body – ensures the payload hasn’t been tampered with.
Headers I receive:
- X-LC-Signature – the digital signature (Base64 encoded)
- X-LC-Signature-Algo – algorithm used (e.g., “SHA256withRSA”)
- X-LC-Transmission-Time – when it was sent
- X-LC-Application – the application ID
- X-LC-Webhook – the webhook ID
The “Secret Key” in Trados UI:
Confusingly named – it’s actually the public key I use to verify the signature. Trados signs with their private key; I verify with this public key.
Verification steps:
- Calculate CRC32 of the raw request body
- Build the message string: transmissionTime|applicationId|webhookId|crc32
- Decode the Base64 signature from the header
- Use the public key to verify the signature matches the message
In practice many integrations skip this entirely – they rely on:
- HTTPS (can’t be intercepted)
- Obscure URLs (hard to guess)
- Short-lived tunnel URLs (like TCC uses)
But for production systems receiving webhooks on a permanent public endpoint, verification matters. It proves the request genuinely came from Trados, not someone spoofing the endpoint.
Wrapping up…
So what have I learned? Webhooks are simpler than they first appear – they’re just Trados tapping your integration on the shoulder saying “something happened.” The complexity comes from the volume (you get everything, not just what you care about) and understanding the difference between being notified and being authorised to act.
If you’re implementing a Trados integration, or working with a team who is, I hope this article goes a little way towards demystifying what’s going on under the hood. And if you want to see it for yourself without writing any code, give the Trados Callback Catcher a try – watching those webhooks roll in makes the whole concept click in a way that documentation alone never quite manages… at least it has for me and I had a lot of fun building it.
If you have questions, spot something I’ve got wrong, or just want to share your own webhook war stories, drop a comment below.
For those who made it this far 🙂
You can find two documents that might be helpful when developing, or troubleshooting, webhooks at the following locations:
- TCC – Trados Cloud API Reference: Essential Trados Cloud API details used by TCC
- authentication flow,
- webhook setup/payloads,
- batched delivery,
- signature headers,
- retry policy,
- service user identity,
- project tasks API for highlighting,
- and rate limit mitigation.
- TCC – Troubleshooting Report Reference: Field-by-field explanation of the troubleshooting window
- what each diagnostic value means,
- how to interpret it for debugging,
- and security risk levels (🟢/🟡/🟠/🔴) for public sharing guidance.