Integrate a SaaS platform on Stripe or Adyen
Connect Stripe or Adyen once and Coris runs its checks from your processor events. On Stripe, add payment context with POST /transaction_metadata/ if you need it.
Connect Stripe in the portal, or have Coris connect Adyen, and processor events then drive Coris. Many platforms make no API call, and yours never calls Merchant Profiler or CorShield directly. On Stripe, add payment context with POST /transaction_metadata/.
- Your platform → Coris1Connect your processor
- Stripe or Adyen → Coris2Connected account event
- Coris3Match the business and create the account
- Coris4Run your onboarding monitoring
- Coris5Run Merchant Profiler and CorShield data as your rules require
- Coris → Your platform6Webhook:alert.created,
account.tag.created - Stripe or Adyen → Coris7Payment, payout and dispute events
- Coris8Run your monitoring
- Coris → Your platform9Webhook and portal
- Your platform → Coris10Stripe only:POST
/ transaction_metadata/
Data you send and receive
| Source | Data |
|---|---|
| Processor to Coris | Connected accounts, persons, payments, payouts, disputes |
| You to Coris | Transaction metadata, plus optional tags and lists |
| Coris to you | Webhook events and portal views |
Setup checklist
Connect your processor first.
- Connect Stripe in the portal. For Adyen, ask Coris to connect it.
- Set up your onboarding and monitoring rules. Coris can help.
- Review alerts in the portal.
For API calls only:
- Create an API key.
- Register a webhook endpoint.
Events to enable
Processor events run your agreed monitoring, including Merchant Profiler data and CorShield when your rules use them. With no rules, no monitoring runs.
On Stripe you enable nothing, because Coris creates its webhook endpoints when you connect. For a security review, Stripe access covers the events and key access. To learn how charge types affect monitoring, ask Coris.
On Adyen, send these events to the webhook URL Coris gives you:
balancePlatform.accountHolder.created,balancePlatform.accountHolder.updatedbalancePlatform.balanceAccount.created,balancePlatform.balanceAccount.updatedbalancePlatform.transfer.created,balancePlatform.transfer.updatedAUTHORISATION,CAPTURECHARGEBACK,REQUEST_FOR_INFORMATION,NOTIFICATION_OF_CHARGEBACK,SECOND_CHARGEBACK,CHARGEBACK_REVERSED,NOTIFICATION_OF_FRAUD
Endpoints you use
| Job | Endpoint |
|---|---|
| Add payment context | Update transaction metadata |
| Receive results | Create a webhook endpoint |
| Optional: add account data | Update account metadata |
| Optional: label a merchant | Set an account tag |
Add payment context
Step 1: Set your base URL and key
Every sample below uses these values.
export CORIS_BASE_URL="https://sandbox-api.coris.ai/api/v0_2"
export CORIS_API_KEY="YOUR_API_KEY"import time
import requests
BASE_URL = "https://sandbox-api.coris.ai/api/v0_2"
HEADERS = {"Authorization": "Token YOUR_API_KEY"}const BASE_URL = "https://sandbox-api.coris.ai/api/v0_2";
const HEADERS = {
Authorization: "Token YOUR_API_KEY",
"Content-Type": "application/json",
};Step 2: Add metadata to a Stripe payment
Attach your own fields to one Stripe payment, by ch_ ID with stripe_charge or pi_ ID with stripe_payment_intent. Read back with the same type, because a charge and its payment intent do not share metadata.
Until the payment reaches Coris, GET returns 404 and Coris holds what you post. You cannot list or cancel held metadata. Coris applies it in order on arrival, so a later post with null removes that key.
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
"$CORIS_BASE_URL/transaction_metadata/?source_transaction_type=stripe_charge&source_transaction_id=ch_1AcmeExample" \
-H "Authorization: Token $CORIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "job_type": "water_heater_install" }'response = requests.post(
f"{BASE_URL}/transaction_metadata/",
params={
"source_transaction_type": "stripe_charge",
"source_transaction_id": "ch_1AcmeExample",
},
headers=HEADERS,
json={"job_type": "water_heater_install"},
)
print(response.status_code)const query = new URLSearchParams({
source_transaction_type: "stripe_charge",
source_transaction_id: "ch_1AcmeExample",
});
const txnMetadata = await fetch(`${BASE_URL}/transaction_metadata/?${query}`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({ job_type: "water_heater_install" }),
});
console.log(txnMetadata.status);Step 3 (optional): Add metadata to an account
Store data about a merchant on its account, with your Stripe account ID in the path. The call returns 404 until that account exists in Coris. Set a value to null to remove a key.
curl -s -X POST "$CORIS_BASE_URL/accounts/acct_1AcmeExample/metadata/" \
-H "Authorization: Token $CORIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "plan": "pro", "signup_channel": "partner" }'response = requests.post(
f"{BASE_URL}/accounts/acct_1AcmeExample/metadata/",
headers=HEADERS,
json={"plan": "pro", "signup_channel": "partner"},
)
print(response.status_code, response.text)const metadata = await fetch(`${BASE_URL}/accounts/acct_1AcmeExample/metadata/`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({ plan: "pro", signup_channel: "partner" }),
});
console.log(metadata.status, await metadata.text());Step 4 (optional): Keep a custom list
Keep a list of IDs or terms in Coris. list_type tells Coris how to use the list.
curl -s -X POST "$CORIS_BASE_URL/settings/custom_list/" \
-H "Authorization: Token $CORIS_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Trusted accounts $(date +%s)\",
\"description\": \"Accounts your team has reviewed\",
\"list_type\": \"account_ids\",
\"items\": [\"acct_1AcmeExample\"]
}" | jqresponse = requests.post(
f"{BASE_URL}/settings/custom_list/",
headers=HEADERS,
json={
"name": f"Trusted accounts {int(time.time())}",
"description": "Accounts your team has reviewed",
"list_type": "account_ids",
"items": ["acct_1AcmeExample"],
},
)
print(response.status_code, response.json())const list = await fetch(`${BASE_URL}/settings/custom_list/`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
name: `Trusted accounts ${Date.now()}`,
description: "Accounts your team has reviewed",
list_type: "account_ids",
items: ["acct_1AcmeExample"],
}),
});
console.log(list.status, await list.json());Read the response
The custom list call returns the list you created. Step 2 returns 202 with an empty body.
{
"id": "d29a7c14-3b6e-4f08-95c1-7e2b0a6d8f33",
"name": "Trusted accounts 1762300800",
"description": "Accounts your team has reviewed",
"list_type": "account_ids",
"items": ["acct_1AcmeExample"]
}| Field | What to do |
|---|---|
id | Use it to update the list. |
list_type | Pick the type that matches your items. |
items | Send the full list on update. |
What to do next
| Event | Your action |
|---|---|
alert.created | Review it in the portal. See Monitor your portfolio. |
transaction.alert.created | Route it. See Triage transaction alerts. |
| A Stripe dispute | Work it in the portal. See Respond to disputes. |
For your risk, compliance and security reviewers: How Coris checks work, Monitoring and alerts explained and Security and compliance.
FAQ
What must a Stripe account have before Coris onboards it?
It needs accepted terms of service and enough business details for a search. Until then, Coris waits for a later event. An account can exist in Coris before this, and onboarded turns true once onboarding has run.
Are new accounts monitored?
Yes, by default. See Monitor your portfolio.
Can I add metadata to an Adyen payment?
No, only Stripe payments. On Adyen, use Update account metadata.
Do tags I send trigger webhooks?
Yes. Each change sends an account.tag.* event to subscribed endpoints. Filter out changes your own system made.
Next: Connect Stripe and Adyen
Updated about 3 hours ago