Credit Line — Draws

A draw facility is a credit line your customer takes money from on demand. They are approved once for a facility limit and accept a master agreement during onboarding; from then on, each draw is a financed advance under that agreement — the customer picks an amount and a repayment plan, and repays it in fixed installments. Several draws can be running at the same time.

This is one of the two credit line types Slate offers:

Draws (this guide) Revolving
The customer... takes draws when they need cash spends on a card you operate
Repayment fixed installments per draw statement balance each period
Billing none — each draw has its own schedule 7-day periods, statements, minimum payments
You push nothing every purchase and payment, in real time
Typical for payroll funding, working capital on demand fuel/fleet cards, B2B spend

All amounts are integer cents (e.g. 50000 = $500.00). All dates are YYYY-MM-DD. Requests are authenticated with your private API key in the x-api-key header. Webhooks are signed — see Webhooks.


Lifecycle at a glance

You create the customer ──► You attach financial data ──► Slate underwrites


                                  Pre-approval issued ──► webhook: preapproval.created

                              the banner shows the offer       │
                              the customer activates           │

Application approved ──► Slate activates the line ──► ACTIVE (nothing owed yet)

                        ┌────────────────────────────┘

              Customer draws an amount + picks a plan


              Agreement created ──► webhook: credit-line.draw.created
              Schedule A emailed to the customer


              Slate disburses ──► webhook: financing-agreement.disbursed


              Fixed installments collected
              ──► webhook: financing-agreement.repayment (each one)

          ┌─────────────┴──────────────┐
          ▼                            ▼
   Draw fully repaid            Draw unpaid past its last payment
   financing-agreement.completed        line is SUSPENDED
   availability restored               webhook: credit-line.suspended


                                       Terms renegotiated with Slate
                                       webhook: credit-line.reinstated

Key facts:

  • No billing periods and no statements. Those belong to the revolving type. Here, each draw carries its own payment schedule.
  • One master agreement. The customer accepts it once, during the credit line application. Each draw is executed under it and only generates a Schedule A (the cover with its amount, rate and schedule) — never a new agreement to accept.
  • Availability is consumed by principal, not by the total to repay. A $5,000 draw at a 1.2 factor rate means $6,000 to repay, but it uses $5,000 of the limit. Availability recovers as principal is repaid.
  • Pricing is the plan's factor rate. No management fees on draws.
  • Multiple draws can run at once, each with its own schedule and status.

Step 1 — Create the customer

Create the customer with your own stable identifier (externalId) — it is your reconciliation key across every Slate object. A customer is either a BUSINESS or a PERSON.

curl -X POST "$BASE_URL/customers" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "BUSINESS",
    "externalId": "cus_123",
    "productType": "credit_line",
    "business": {
      "legalName": "Acme Corp",
      "dba": "Acme",
      "website": "https://acme.com"
    }
  }'

A customer is enrolled in exactly one product. If your organization has more than one product active at the same time, productType is required, it tells Slate which product or money facility this customer is being offered (here, "credit_line"). With a single active product you can omit the field: the customer is assigned the product your program was set up with when you started with Slate.

All detail fields are optional at creation — whatever you don't provide, the customer fills in during the application. The more you provide upfront, the shorter their application. If the customer already exists (for example, they already use another Slate product), skip this step.

Webhook — customer.created confirms the customer exists; data.id is the customer id.

Step 2 — Attach financial data

Submit the customer's financial history so Slate can underwrite. The payload is a timeseries keyed by your externalId:

curl -X POST "$BASE_URL/attach-financial-data" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "cus_123",
    "timeseries": [
      { "date": "2026-04-01", "data": { "revenue": 4200000, "payrollTotal": 1850000, "employees": 24 } },
      { "date": "2026-05-01", "data": { "revenue": 4550000, "payrollTotal": 1920000, "employees": 25 } },
      { "date": "2026-06-01", "data": { "revenue": 4830000, "payrollTotal": 1980000, "employees": 26 } }
    ]
  }'

The data object is free-form — send the metrics agreed with Slate for your integration (revenue is the baseline; a payroll platform typically adds payroll volume and headcount). You can attach new data at any time to keep the picture current; fresher data means better offers.

Webhook — business.financial-data.attached confirms ingestion; data.id is the financial data record id.

Step 3 — Slate issues a pre-approval

When the customer qualifies, Slate creates a pre-approval — a non-binding offer whose amount is the facility limit Slate is prepared to extend on a credit line. You receive:

Webhook — preapproval.created

{
  "event_type": "preapproval.created",
  "data": { "id": "019f8186-7021-73ea-a169-b12cd581c38c" },
  "timestamp": "2026-06-18T16:32:00Z"
}

Fetch the customer's offers any time:

curl "$BASE_URL/v2/pre-approvals?externalId=cus_123&status=ACTIVE" \
  -H "x-api-key: $API_KEY"

A pre-approval is ACTIVE until it either expires (webhook preapproval.expired) or the customer converts it by completing an application (webhook preapproval.consumed).

Step 4 — Show the line in your product

Everything the customer sees is rendered by Slate components, authenticated with a short-lived session token that you mint server-side for the logged-in customer:

curl -X POST "$BASE_URL/user-session-token" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "externalId": "cus_123" }'
{ "token": "eyJhbGciOi..." }

Never expose your API key to the browser, only the session token. Load the components bundle once per page:

<script async type="module" src="https://components.tryslatehq.com/slate.esm.js"></script>

You have two options for implementing the flow, from least to most integration work:

One component covers the entire journey — the offer, the activation, and the line once it is live. It reads the customer's state on its own and renders the right thing, opening Slate's flows when clicked. Drop it in and you're done.

<slate-credit-line-banner
  env="live"
  user-token="<session-token>"
></slate-credit-line-banner>
Customer state What the banner shows Button
Pre-approved, no line yet "Activate your credit line" Activate → opens the application
Application in progress "Finish activating your credit line" Resume → reopens where they left off
Application submitted "We're reviewing your application"
Line active Available amount and how much of the limit is in use Draw funds → opens the draw flow
Line paused The line and its balance, draws disabled
No offer and no line Renders nothing (takes no space)

The banner only speaks credit line: if the customer's offer belongs to the capital product, it renders nothing. That makes it safe to embed on a page every customer sees — each customer gets their product's banner, never the wrong copy.

The banner inherits your brand colors from the branding you configure with Slate. See the Credit Line Banner component page for all its properties and caveats.

Option B — Your own banner + slate-application-form

Build the banner/offer UI yourself and open Slate's application form when the customer engages. You drive your banner's state by listening to the webhooks (preapproval.*, application.*, credit-line.*) or by polling GET /v2/pre-approvals, GET /v2/applications and GET /credit-lines?externalId=..., and embed only the flow itself.

The same component serves both moments of the journey — the draw attribute is what tells them apart:

The customer... How to embed it What it opens
has no active line yet slate-application-form as-is The full application to activate the line
already has an active line slate-application-form with draw The two-screen draw flow

Activating the line — the customer has a pre-approval but no line yet:

<slate-application-form
  id="application-form"
  env="live"
  user-token="<session-token>"
  closable
></slate-application-form>

<script>
  const form = document.getElementById("application-form");
  form.addEventListener("submit", ({ detail }) => {
    // detail.applicationId — the application was submitted
  });
  form.addEventListener("dismiss", ({ detail }) => {
    // detail.status is "submitted" | "approved" | "rejected" — close the form
  });
</script>

Taking a draw — the customer's line is already active:

<slate-application-form
  id="draw-form"
  env="live"
  user-token="<session-token>"
  draw
  closable
></slate-application-form>

Passing draw is not cosmetic: without it the customer would be starting a new credit line application, and with it the same session opens a draw against the line they already have — amount, plan and confirmation only, no onboarding steps and no second agreement to accept. Send it only once the line is active; check with GET /credit-lines?externalId=... if you are not tracking the state from the webhooks.

The form renders as an iframe that fills its parent, so give the container an explicit height. See the Application Form component page for all its properties, events and caveats.

Step 5 — The customer activates the line

Clicking Activate opens Slate's application. The customer confirms their details, connects their bank account, verifies identity if required, and accepts the terms and conditions and the master agreement — the agreement that governs every future draw. There is no amount or terms selection in this flow: the customer is activating a line, not borrowing yet.

Webhook — application.submitted fires when they finish. Slate then reviews it:

Webhook — credit-line.approved

{
  "event_type": "credit-line.approved",
  "data": { "id": "9c5f8f4e-...-application-uuid" },
  "timestamp": "2026-06-20T16:32:00Z"
}

data.id is the application id, and the application now carries the approved maximum facility limit:

curl "$BASE_URL/v2/applications/{applicationId}" \
  -H "x-api-key: $API_KEY"

Step 6 — Slate activates the line

Once the application is approved, Slate activates the credit line for the agreed facility limit — you don't call anything. (The POST /applications/{applicationId}/credit-line endpoint you may see in the API reference belongs to the revolving type, where the partner sets and confirms the card's limit.)

The line goes live with nothing owed and the full limit available. Slate emails the customer to tell them their line is ready, and you receive:

Webhook — credit-line.created

{
  "event_type": "credit-line.created",
  "data": { "id": "019f8186-7021-73ea-a169-b12cd581c38c" },
  "timestamp": "2026-06-22T14:03:11Z"
}

data.id is the credit line id — the id every subsequent credit line webhook refers to. Store it against your customer, or resolve it any time from your own identifier:

curl "$BASE_URL/credit-lines?externalId=cus_123" \
  -H "x-api-key: $API_KEY"

If you use the banner, there is nothing to do here at all: it switches to the active state on its own.

Repayment plans

The plans a customer can choose from when drawing — how many months and at what factor rate, for example 3 / 6 / 9 monthly payments — are configured with Slate per customer, using your partner-level defaults as the starting point. They are set before the customer's first draw. Changing a customer's plans never reprices draws they already took.

Step 7 — The customer draws

With an active line, the banner's Draw funds button opens a two-screen flow: the customer picks an amount (up to their available credit) and one of their repayment plans, sees the exact schedule and total to repay, and confirms.

That confirmation is the whole transaction. Slate:

  • creates a financing agreement for the draw, priced at the plan's factor rate,
  • records the customer's acceptance under the master agreement they already signed,
  • emails them the Schedule A with the amount, rate, payment amount and full schedule.

Webhook — credit-line.draw.created

{
  "event_type": "credit-line.draw.created",
  "data": {
    "id": "019f8186-7021-73ea-a169-b12cd581c38c",
    "financingAgreementId": "01a1b2c3-..."
  },
  "timestamp": "2026-06-25T18:40:12Z"
}

data.id is the credit line; financingAgreementId is the draw itself. Fetch it for the amount, rate and schedule:

curl "$BASE_URL/v2/financing-agreements/{financingAgreementId}" \
  -H "x-api-key: $API_KEY"

You also receive financing-agreement.created for the same agreement.

Step 8 — Disbursement

Slate disburses the draw to the customer's connected bank account.

Webhook — financing-agreement.disbursed — the money is on its way, and Slate emails the customer to confirm it. Show it in your UI too; funds typically land in 1–2 business days.

Step 9 — Repayment

Each draw repays on its own schedule, collected by pre-authorized debit from the customer's account.

Webhook — financing-agreement.repayment fires on every collected payment. Fetch the agreement to show the updated remainingBalance and totalPaid.

Webhook — financing-agreement.completed fires when a draw is fully repaid. Its principal stops consuming the limit, so the customer's available credit goes back up.

If you collect the payments

If both sides agreed that you collect the customer's payments and remit them to Slate on a pre-established schedule, your integration is configured for partner-managed collections. In that setup Slate never debits the customer — you report each payment you collected with this endpoint, and Slate settles it against the draw:

curl -X POST "$BASE_URL/financing-agreements/{financingAgreementId}/payments" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 200000,
    "currency": "CAD",
    "externalId": "collection_8f2c31"
  }'

externalId is your idempotency key — re-sending the same one is a no-op, so retries are safe.

Step 10 — Present the line and its draws to your customer

Your customer needs a place to see their line and what they owe on it. Two ways to build it:

Option A — Embed slate-capital

The same dashboard component that powers the capital experience. For a credit line customer it renders the credit line banner on top — available amount and the Draw funds button, or the activation states before the line exists — and underneath it lists the draws of the line: details, repayment progress and the payment schedule of each one. The customer can also make an early payment on a draw: they pick an amount and authorize a PAD debit for it, reducing that draw's remaining balance ahead of schedule.

<slate-capital env="live" user-token="<session-token>"></slate-capital>

You don't need a separate embed per product. A customer is enrolled in exactly one product, and slate-capital evaluates which one from the customer's own offer — the same mount shows a capital customer their capital dashboard and a credit line customer their line. If you offer both products, this is the whole integration. The product="credit-line" attribute still works as an explicit override, but it is no longer required:

<!-- optional override — forces the credit line experience regardless of the customer's offer -->
<slate-capital env="live" user-token="<session-token>" product="credit-line"></slate-capital>

See the Capital Page component page for all its properties and caveats.

Because slate-capital already embeds its product's banner, never place it on the same page as a standalone slate-credit-line-banner or slate-pre-approval-banner-v2 — the banner would render twice.

Option B — Build your own screen

Everything you need is in two endpoints: GET /credit-lines/{creditLineId} for the line's totals (limit, available credit, outstanding balance) and GET /credit-lines/{creditLineId}/agreements for the draws behind them — each with its terms, progress, payment history and upcoming schedule. Refetch after every financing-agreement.repayment and credit-line.draw.created webhook to keep it current.

Step 11 — What the customer owes and can draw

Two endpoints answer everything. The line gives you the totals:

curl "$BASE_URL/credit-lines/{creditLineId}" \
  -H "x-api-key: $API_KEY"
{
  "id": "019f8186-...",
  "status": "active",
  "facilityLimit": 2500000,
  "currency": "CAD",
  "availableCredit": 2000000,
  "balance": {
    "currency": "CAD",
    "balance": 600000,
    "totalOutstanding": 600000
  },
  "createdAt": "2026-06-22T14:03:11.000Z",
  "updatedAt": "2026-06-25T18:40:12.000Z"
}

Read the two numbers carefully — they answer different questions:

  • availableCredit — what the customer can draw right now. It is the limit minus the principal still outstanding.
  • balance.totalOutstanding — what the customer still owes: principal plus the fees not yet paid.

In the example: a $5,000 draw at a 1.2 factor rate means $6,000 owed, but only $5,000 of the $25,000 limit is in use — so $20,000 remains available. As installments are collected, fees are paid first and availability recovers with each payment's principal portion.

And the agreements endpoint gives you the draws behind those totals:

curl "$BASE_URL/credit-lines/{creditLineId}/agreements?status=IN_PROGRESS" \
  -H "x-api-key: $API_KEY"

Each entry is a draw with its amount, rate, remainingBalance and totalPaid — everything you need to render the customer's open draws.

Step 12 — Delinquency

If a draw passes its final payment date with a balance still owed, Slate suspends the line:

Webhook — credit-line.suspended — no new draws are accepted. Existing draws keep their schedules and collections continue.

Getting back to active is a conversation: Slate works out new terms with the customer (which replaces the unpaid draw with a renegotiated one), and once no overdue draws remain the line reactivates:

Webhook — credit-line.reinstated — this is the reactivation signal: the line is active again and draws are accepted. Because the renegotiation creates a replacement draw, you also receive a credit-line.draw.created carrying its agreement.


Monitoring endpoints

Endpoint What it returns
GET /credit-lines?externalId=cus_123 The customer's lines — the way to resolve a line from your own customer id
GET /credit-lines/{creditLineId} A single line: status, limit, available credit and outstanding balance
GET /credit-lines/{creditLineId}/agreements The line's draws, newest first. Filter with status
GET /v2/financing-agreements?creditLineId=... The same draws through the agreements API, paginated
GET /v2/financing-agreements?hasCreditLine=true Every draw across all your customers' lines
GET /v2/financing-agreements?hasCreditLine=false Only regular capital agreements, excluding draws
GET /v2/financing-agreements/{id} One draw: amount, rate, payments made and upcoming schedule

Webhooks summary

Subscribe to these events (see Webhooks for delivery and signature verification).

Event data.id refers to When it fires What you should do
customer.created Customer The customer was created Store the customer id
business.financial-data.attached Financial data record Financial data was ingested Nothing — confirmation only
preapproval.created Pre-approval Slate issued a facility limit offer Nothing if you use the banner — it shows the offer on its own
preapproval.expired Pre-approval The offer expired unused Nothing if you use the banner
credit-line.approved Application The application is approved with a maximum limit Nothing — Slate activates the line (Step 6)
credit-line.created Credit line The line is live Store the credit line id
credit-line.draw.created Credit line A draw was created (financingAgreementId carries it) Fetch the agreement and show the draw
financing-agreement.created Financing agreement The draw's agreement exists Reflect it in your UI
financing-agreement.disbursed Financing agreement The money was sent Tell the customer funds are on the way
financing-agreement.repayment Financing agreement An installment was collected Refresh the draw's balance
financing-agreement.completed Financing agreement A draw was fully repaid Refresh availability — the limit freed up
credit-line.suspended Credit line A draw went unpaid past its final payment date Show the line as paused; no new draws
credit-line.reinstated Credit line Terms were renegotiated and no overdue draws remain Show the line as active again

Good practices

  • Treat webhooks as notifications, not payloads. They carry ids — fetch the current state from the API afterward.
  • Read availableCredit from the line, never compute it. Availability follows principal, not the amount owed; deriving it from balances will drift.
  • Resolve lines by externalId. You never need to store Slate's customer id to find a customer's line.
  • Let the banner own the offer states. It already renders pre-approved, resume, submitted, active and paused — rebuilding that logic is the most common source of drift.
  • Expect several open draws. A customer can draw again while repaying, so list them rather than assuming one.