Scheduled Stripe reports: failed payments, balance, new customers

Three Stripe jobs founders and finance teams set up again and again, each one a few lines of JSON instead of a scheduled function.

Example: past-due subscriptions to Slack every morning

json
{
  "name": "Past-due subscriptions to #revenue",
  "cron": { "expression": "0 9 * * 1-5", "time_zone": "America/New_York" },
  "nodes": [
    { "id": "subs", "stripe_list_subscriptions": { "credential_id": "YOUR_STRIPE_KEY_ID", "status": "past_due", "limit": 100 } },
    { "id": "lines", "transform": { "template": "{ \"count\": \"{{ $.data.length }}\", \"lines\": { \"{{#each $.data}}\": \"• <https://dashboard.stripe.com/customers/{{ $.customer }}|{{ $.customer }}>: <https://dashboard.stripe.com/invoices/{{ $.latest_invoice }}|unpaid invoice>\" } }" } },
    { "id": "post", "slack_send_message": {
        "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX",
        "text": "*{{ $.count }} subscriptions are past due*\n{{ join($.lines, \"\\n\") }}" } }
  ]
}

Example: your balance by email

json
{
  "name": "Stripe balance email",
  "cron": { "expression": "30 7 * * *", "time_zone": "America/Chicago" },
  "nodes": [
    { "id": "balance", "stripe_retrieve_balance": { "credential_id": "YOUR_STRIPE_KEY_ID" } },
    { "id": "email", "smtp_send_email": {
        "credential_id": "YOUR_GMAIL_CREDENTIAL_ID",
        "to": "founder@acme.com",
        "subject": "Stripe: {{ $.available[0].amount / 100 }} {{ $.available[0].currency }} available",
        "text": "Available: {{ $.available[0].amount / 100 }} {{ $.available[0].currency }}\nPending: {{ $.pending[0].amount / 100 }} {{ $.pending[0].currency }}" } }
  ]
}

Stripe amounts are in the smallest currency unit, so / 100 turns cents into dollars.

Example: new customers into your CRM

json
{
  "name": "Stripe customers to CRM",
  "cron": { "expression": "*/15 * * * *" },
  "nodes": [
    { "id": "customers", "stripe_list_customers": { "credential_id": "YOUR_STRIPE_KEY_ID", "limit": 100 } },
    { "id": "upsert", "request": {
        "method": "POST",
        "endpoint": "https://crm.example.com/api/contacts/batch-upsert",
        "credential_id": "YOUR_CRM_TOKEN_ID",
        "body": "{ \"contacts\": { \"{{#each $.data}}\": { \"email\": \"{{ $.email }}\", \"name\": \"{{ $.name }}\", \"stripe_id\": \"{{ $.id }}\" } } }" } }
  ]
}

Set up

Create a restricted key with read access to only what the job needs (subscriptions, customers, or balance), and save it as a bearer_token credential. For anything the built-in steps don't cover, a request step can call any Stripe endpoint with the same credential.

Reference

List Stripe subscriptions: stripe_list_subscriptions

Sends GET https://api.stripe.com/v1/subscriptions. Output for the next step: Stripe’s list: data, each subscription with id, customer, status and latest_invoice.

Field Type Notes
credential_id string, required The id of a bearer_token credential holding a Stripe secret or restricted key (sk_… or rk_…) that can read subscriptions.
status string active, past_due, unpaid, canceled, incomplete, trialing or all. Omit for Stripe’s default (everything but canceled).
limit integer 1 to 100. Omit for Stripe’s default of 10.

List Stripe customers: stripe_list_customers

Sends GET https://api.stripe.com/v1/customers. Output for the next step: Stripe’s list: data, newest first, each customer with id, email, name and created.

Field Type Notes
credential_id string, required The id of a bearer_token credential holding a Stripe key that can read customers.
limit integer 1 to 100. Omit for Stripe’s default of 10.

Read your Stripe balance: stripe_retrieve_balance

Sends GET https://api.stripe.com/v1/balance. Output for the next step: Stripe’s balance: available and pending, each a list of {amount, currency} in the smallest currency unit (cents).

Field Type Notes
credential_id string, required The id of a bearer_token credential holding a Stripe key that can read the balance.