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 areYYYY-MM-DD. Requests are authenticated with your private API key in thex-api-keyheader. 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:
Option A — slate-credit-line-banner (recommended)
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-capitalalready embeds its product's banner, never place it on the same page as a standaloneslate-credit-line-bannerorslate-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
availableCreditfrom 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.