Skip to content

Repository files navigation

fastapi-sample

Marketo SSFS (Self-Service Flow Action) provider — a FastAPI service that plugs into Marketo Smart Campaigns as a custom flow-step action, assigning a random name/email to a lead via the async callback contract.

New to this repo? See AUTH_AND_ENDPOINTS.md for a plain-language walkthrough of how auth works, how to use the OAuth client ID/secret, and what each endpoint does.

Layout

.
├── main.py                 # app entry, wires routers
├── auth_methods/
│   ├── auth.py              # Basic auth check
│   ├── api_key.py           # x-api-key check
│   ├── oauth.py              # OAuth2 client-credentials issuance/validation
│   ├── oauth_router.py       # POST /oauth/token
│   └── optional_auth.py      # accepts Basic, x-api-key, or Bearer for SSFS routes
├── utils/
│   └── users.py             # random name/email helpers used by the SSFS callback
├── ssfs/
│   ├── routes.py             # Marketo flow action (Adobe path names)
│   ├── default_routes.py     # optional SSFS endpoints (icons, instructions, picklist)
│   ├── security_schemes.py   # shared OpenAPI security scheme definitions
│   ├── openapi_loader.py     # loads/patches ssfs/openapi.json at request time
│   └── openapi.json          # SSFS spec for Marketo install
├── scripts/
│   └── validate_ssfs.py       # validates ssfs/openapi.json against Adobe's schema
├── tests/
├── .env.example
└── requirements.txt

Routes

Route Auth Purpose
GET /health none Liveness probe
GET / none Links to docs and Marketo install URL
GET /install none Marketo SSFS OpenAPI spec
POST /oauth/token none Issues a Bearer token (client-credentials grant)
GET /brandIcon none Provider brand logo shown in Admin → Service Providers
GET /serviceIcon none Flow-step icon shown in the Campaign Flow Palette
GET /getServiceDefinition Basic/apiKey/Bearer* SSFS service definition
GET /status Basic/apiKey/Bearer* SSFS health for Marketo nightly poll
POST /submitAsyncAction Basic/apiKey/Bearer* SSFS async flow step + callback
GET /providerInstructions Basic/apiKey/Bearer* HTML setup instructions
POST /getPicklist Basic/apiKey/Bearer* Picklist choices for flow parameters

*Auth is enforced only when the corresponding env vars are set (MARKETO_USER/MARKETO_PASSWORD, MARKETO_API_KEY, or OAUTH_CLIENT_ID/OAUTH_CLIENT_SECRET). /brandIcon and /serviceIcon are always public per the Adobe SSFS spec — Marketo renders the flow-step palette entry from them.

Run locally

Requires Python 3.13 (see .python-version).

python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
cp .env.example .env   # optional
uvicorn main:app --reload --port 8088

Environment variables

Copy .env.example to .env. All are optional for local dev.

Variable Purpose
SSFS_AUTH_MODE Which scheme is listed first in /install security: basic (default), apiKey, or oauth2
MARKETO_USER / MARKETO_PASSWORD Basic auth credentials for SSFS routes
MARKETO_API_KEY API key for the x-api-key header
OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET OAuth2 client-credentials for POST /oauth/token
API_BASE_URL Overrides servers.url in /install and /openapi.json
SSFS_BRAND_ICON_PATH / SSFS_SERVICE_ICON_PATH Custom SVG/PNG paths for Marketo UI icons
SSFS_PROVIDER_INSTRUCTIONS_PATH Custom HTML for /providerInstructions

Try it

curl http://localhost:8088/install
curl -u marketo:secret http://localhost:8088/getServiceDefinition
curl -u marketo:secret http://localhost:8088/status

Deploy on Replit

.replit and replit.nix are checked in so you can fork this repo straight into Replit and get a public HTTPS URL.

  1. Import this repo into Replit (New Repl → "Import from GitHub").
  2. Open the Secrets panel and add whichever auth env vars you plan to use — at minimum MARKETO_USER and MARKETO_PASSWORD (or MARKETO_API_KEY, or OAUTH_CLIENT_ID/OAUTH_CLIENT_SECRET). Also set SSFS_AUTH_MODE if you want a scheme other than basic shown first in /install.
  3. Set API_BASE_URL in Secrets to your Repl's public URL (e.g. https://your-repl.your-username.repl.co) so /install advertises the right server URL to Marketo.
  4. Hit Run. The first boot installs deps into /tmp/venv (that step is skipped on subsequent runs, so restarts are fast).
  5. For a stable production URL, click Deploy — that uses the [deployment] block in .replit to run on Cloud Run with 2 workers.

Once it's up, https://<your-repl-url>/install is what you paste into Marketo Admin → Service Providers.

Why the extra install step vs. other Replit examples: this project uses pip + requirements.txt. Some public reference implementations (like tyron-pretorius/marketoSSFS) use Poetry + pyproject.toml instead — Replit auto-installs Poetry deps as part of the Nix env, so their run = line has no install step. Here you'll see a one-liner in .replit that bootstraps a venv under /tmp/venv on first Run and reuses it after; that's the pip equivalent of what Replit does for free with Poetry projects.

Heads up: Replit tends to shift things around over time (image contents, PORT env behavior, deploy workflow). If the Run button fails, check the Replit shell for the actual error — nine times out of ten it's either a missing Secret (401 on Marketo routes) or python3 -m ensurepip --upgrade needing to run once manually to bootstrap pip. The [deployment] build step in .replit handles both automatically.

Marketo SSFS

Adobe Self-Service Flow Actions require fixed path names (/submitAsyncAction, etc.) and a validated OpenAPI file. That contract lives in ssfs/ — the rest of the app is normal Python.

  1. Deploy the app somewhere publicly reachable over HTTPS.
  2. Set MARKETO_USER/MARKETO_PASSWORD (or MARKETO_API_KEY, or OAUTH_CLIENT_ID/OAUTH_CLIENT_SECRET).
  3. In Marketo: Admin → Service Providers → Add New Service.
  4. Install URL: https://<your-host>/install
  5. Enter the matching credentials when prompted.
  6. In a Smart Campaign's flow editor, add the Random User Email flow step.

The flow step assigns each lead a random generated_email and generated_name via the SSFS callback.

Async contract: POST /submitAsyncAction returns 201 immediately and POSTs the result to Marketo's callbackUrl in a background task (with x-api-key and x-callback-token headers). Synchronous invocation is not supported per the SSFS spec — failed callbacks are logged but do not change the 201 ack.

Tests

source .venv/bin/activate
pytest

Tests cover: /install shape + server-URL rewrite, auth gates for Basic/apiKey/Bearer (401 when wrong, 200 when valid, bypassed when env vars unset), required-field validation on /submitAsyncAction, async 201 ack, callback delivery with correct headers + body (asserted via respx), 201 contract holding when the callback target returns 500 or is unreachable, and the Adobe SPI schema validation in scripts/validate_ssfs.py.

Validate the spec locally (optional):

git clone https://github.com/adobe/Marketo-SSFS-Service-Provider-Interface.git
cd Marketo-SSFS-Service-Provider-Interface
npm install
node -e "require('./scripts/validate').validateFile('$(pwd)/../fastapi-sample/ssfs/openapi.json', './schema.yaml')"

Reference: Adobe Marketo SSFS Service Provider Interface

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages