Service Providers

Credentials for external services live on the cluster, not in your blueprint. Where a block supports it, you give it the name of a provider and it fetches what it needs at the moment of the call, uses it and lets it go, so the key never lands on a pin and never appears in a trace.

Every integration has the same awkward moment. Your flow needs to call Stripe, so it needs the Stripe secret key. The obvious place to put it is on the block's input pin, which means the key is now part of the blueprint, which means everybody who can open that blueprint can read it. Simulation makes it worse rather than better: a trace hands back every value that flowed through the run, so the key is not just stored where developers can see it, it is printed to them each time they check their work.

A service provider moves the credential off the canvas entirely. You configure it once on the cluster, and blueprints refer to it by a name you choose. The block resolves the credential at request time, uses it for that one call, and does not keep it. Nothing about the key reaches a pin, a trace, a log line or the console.

What the blueprint carries

A name. stripe-live, postmark-main, notifications. It is not sensitive, it is readable in the canvas, and it says plainly which account the flow is talking to. Two environments become two providers and one name change.

What the cluster holds

The key, the token, the signing secret, the webhook URL. Written once, never handed back: reading a provider shows every secret field as "set" rather than as its value, no matter who is asking or how they ask.

Setting One Up

Providers are managed in RUAL Studio, alongside the other cluster settings. Creating one takes four decisions.

  1. Pick the type. The type is the service itself: Stripe, Postmark, Anthropic, MessageBird. It decides which fields you are asked for and which of those fields are secret.
  2. Give it a name. This is what your blueprints will say. Name it after the account rather than the vendor when you have more than one: stripe-live and stripe-test beat stripe and stripe2.
  3. Fill in the fields. Secret fields go in once. From then on the studio shows them as set, never as their value, and leaving them untouched on a later edit leaves them unchanged.
  4. Test it. A provider starts untested, and testing it makes a real call against the service. A provider whose credentials you edit goes back to untested, because the previous result no longer describes what is stored.

After that, the provider is either named on a block or reached for by the cluster on its own, depending on the service. The next section is the definitive list of which is which.

A Provider Declares What It Can Be Used For

Every provider type declares the purposes it can serve, and everything that resolves one asks for a specific purpose. That pairing is what makes a provider name safe to type: naming your mail provider on a payment block fails immediately and says why, instead of sending Stripe a Postmark token and leaving you to interpret whatever the remote service says about it.

Providers a block names directly

These blocks have a provider in-pin. Type the provider's name there and no credential exists anywhere in the blueprint.

PurposeProvider typeBlocks
Payments Stripe function_create_stripe, and through the connection it hands out, every checkout, payment, subscription, refund and credit note block
Chat notifications mssgs mssgs_send_message, for posting an operational message into a channel from a flow
Horticulture trade Floriday function_floriday_open_connection and its supplier variant

Providers the cluster uses on its own

These are bound by purpose rather than named on a pin: exactly one provider per entity serves each, and the cluster reaches for it without any blueprint being involved.

PurposeProvider typesWhat uses it
SMS deliveryMessageBird, TwilioTwo-factor codes, passwordless login codes and phone enrolment
Transactional emailPostmark, LettermintThe cluster's own outbound mail
Node reportingmssgsWhere the node reports its own errors and warnings, deliberately a different provider from the one your flows post to

Provider types you can configure ahead of the blocks

These types exist and can be filled in and tested, but nothing resolves them from a blueprint yet. Configuring one now is not wasted: it is where the credential belongs, and the block that reads it is the part still to come. Until then, those integrations still take their key on a pin or from a secure system setting.

PurposeProvider types
AI completionAnthropic
Marketing emailMailchimp
Voice callsTwilio, kept separate from SMS so one account can serve one and not the other
Chat notificationsDiscord
Source controlGitHub
Geo database updatesMaxMind
Map tilesMapbox
Cache and search connectionsRedis, Elasticsearch

What the Cluster Guarantees When a Block Asks

Handing a credential to a block is the moment where this could go wrong, so three rules are enforced on the block's behalf rather than left to it.

RuleWhat it means for you
The credential is never put anywhere the run can read it It does not become part of the connection object, an out-pin, the values a simulation hands back, or a console line. Blocks are written so the connection carries the provider's name and nothing else.
A name only reaches your own providers You can resolve your own, and the ones the hosting entity shares with you. A name is never a route into another tenant's account, however precisely you guess it.
The wrong kind of provider is refused before the credential is fetched Asking for a payment credential and naming a mail provider is an error with a clear code, raised locally. Nothing is sent anywhere and no key changes hands.
A webhook URL is a credential An incoming webhook URL has its token built into the address, so a chat webhook sitting on a pin is a secret sitting on a pin in plain sight. Chat destinations are providers for exactly that reason, and the URL is stored as a secret field like any key.

Rotating a Key Is One Edit

Open the provider, paste the new value, save. Every flow picks it up on its next run: no blueprint is edited, nothing is redeployed, nothing is reactivated. The same applies to swapping accounts, because the flows named a provider rather than an account.

The most common shape is one provider per environment. Point the test blueprint at stripe-test and the live one at stripe-live, and moving from one to the other is a single value on a single block rather than a key nobody wants to paste into a canvas twice.

Compared With the Older Ways

There were two patterns before this, and both still exist. It is worth being clear about when each is the right answer.

Where the value livesUse it forNot for
A service provider Every service in the first two tables above, and any service with a provider type you want the credential stored properly for today. It is the only option where the value cannot be read back out at all. Values that are not credentials, and services with no provider type yet.
A secure system setting Credentials for a service whose blocks do not read a provider yet, such as the Anthropic key, and cluster-wide values a flow reads at runtime. Anything a block can name a provider for. A setting is read by a block, which means the value enters the run and can be printed by the next block along.
A value on a pin Non-secret configuration: an account identifier, a sender address, a region, an API version. Any secret at all. Whatever is on a pin is in the blueprint, readable by anyone who can open it and visible in every simulation of it.
Check which table a service is in before you go looking for a pin Most integration blocks predate providers and still take their key on a pin. A provider type existing for a service does not yet mean a block reads it, so if you cannot find a provider pin, the first table is the definitive list of blocks that have one.

When a Block Cannot Resolve a Provider

What you seeWhat it usually is
The provider is not foundThe name on the block does not match the provider's name, or the provider belongs to a different entity. Names are exact.
The provider is the wrong purposeThe named provider is a real provider of a type that cannot serve this block. Check that the payment block names the payment provider.
The provider is disabledIt exists and is switched off. That is a deliberate state, so somebody turned it off on purpose.
The remote service rejects the callThe credential resolved and the service refused it. Test the provider from the studio: that call goes straight to the service and separates a stale key from a wiring problem.
SMS is not sent and nothing looks wrongOutbound SMS resolves a provider first and falls back to a cluster setting. A cluster whose token only exists in a node configuration file has no credential the platform can see: move it into a provider.

Next Steps

Frequently asked

Where should I store an API key in RUAL?

In a service provider, configured on the cluster, whenever the service has one. Blueprints then refer to it by a name you choose, and the block resolves the credential at the moment of the call, so the key never lands on a pin, never appears in a simulation trace and cannot be read back out. Blocks that do not read a provider yet should take the key from a secure system setting instead, never from a value in the canvas.

How do I rotate an API key in RUAL?

Open the service provider, paste the new value and save. Every flow picks it up on its next run. No blueprint is edited, nothing is redeployed and nothing is reactivated, because the flows named a provider rather than a key.

Why does my RUAL block say the provider is the wrong purpose?

Every provider type declares which purposes it can serve, and every block asks for a specific one. The named provider exists but is a type that cannot serve this block, for example a mail provider named on a payment block. The check happens before any credential is fetched, so nothing was sent anywhere.