# GreyRok Capital Partner API v1.3.0 > An HTTP API for brokers, aggregators and referral partners to submit Australian business loan applications to GreyRok Capital and receive status updates. This file is written for a language model assisting an integration. It is generated from the same modules the API runs on. The request body schema is authoritative at https://partners.greyrokcapital.com.au/api/partner/openapi.json (OpenAPI 3.1, emitted from the validator). Read that for field types. Read this for the behaviour a schema cannot state. ## Changed since 1.0.0 - 1.3.0: Three new optional fields on a submission say who you would like the GreyRok credit team to call about it. `whoToCall` is `client` or `broker`. `callOnBehalfOf` is who you would like GreyRok to say it is calling on behalf of when it calls the client, and is required when `whoToCall` is `client`. `broker` carries the broker's `name` and `phone`, and is required when `whoToCall` is `broker`. All three are shown to the credit team as your request, in the new application email and on the deal. It is a request, not a setting: GreyRok may still contact the applicant directly, for example to complete the full application. A submission without them is accepted exactly as before. - 1.3.0: `notes` is now shown to the credit team in the new application email and on the deal, line breaks included. Until 1.3.0 it was accepted and stored, but not shown to anyone, although this document said it reached the credit team. - 1.2.1: If you receive status updates at a webhook URL, you can ask GreyRok to stop emailing them to your nominated address. That stops every further status email, including on applications already in progress. The one exception is `applicationUnderAssessment` when your applicant completes the full application, which is still emailed, for the reason in the next entry. - 1.2.1: `applicationUnderAssessment` produced by your applicant completing the full application is not currently posted to your webhook; it is emailed. The same event is posted when it comes from the GreyRok credit team. Until 1.2.1 this document said every change of state was posted. - 1.2.0: Three new events for the stretch between the client accepting the offer and the facility funding, each in the `In Progress` group: `contractSent` with the status name `Agreement sent to client` when the loan agreement is sent to the client, `contractSigned` with `Agreement signed` when the client has signed it, and `pendingSettlement` with `Pending settlement` when the application enters GreyRok's final checks before funding. `pendingSettlement` is sent once, however many of those checks the application passes through. - 1.2.0: `applicationFunded` now carries `approvedLoanAmount`, the amount the facility funded at, in whole dollars, whenever GreyRok holds it. It can differ from `requestedLoanAmount`. GET returns the same figure while the application is funded. It is absent otherwise, never zero or null. - 1.1.2: `applicationFunded` is now sent when the facility is funded, not when the client accepts the offer. Earlier versions sent it at acceptance, before the loan agreement was signed. - 1.1.1: A status update that fails with a 5xx, a 408, a 429 or no response is now first retried after 5 minutes, as documented. Until 27 September 2026 the waits between attempts were 15 minutes, 1 hour, 4 hours, 12 hours and 12 hours. - 1.1.1: How to tell a status update came from GreyRok is now documented in full. When you have given GreyRok a secret, every status update carries it as a bearer token in the Authorization header. It is the secret itself, sent over HTTPS, not a signature. Updates were already sent this way. - 1.1.1: The status update schema now matches what is sent. `externalRef` is not required, because it is omitted when GreyRok holds none, as on a test message. `requestedLoanAmount` may be null. `test`, present only on a test message, is documented. - 1.1.1: The sandbox is now described as it is. Until GreyRok's production cutover, the sandbox shares a database with the live base URL, and so shares your partner record: status updates for an application you submit there go to the same webhook URL as live ones. Nothing submitted there is emailed to the credit team or written to the CRM. - 1.1.0: A new event, `applicationInCredit`, with the status name `Waiting for credit to approve` in the `In Progress` group. It is sent when an application goes to the GreyRok credit team for a decision. - 1.1.0: Five new names in the `Rejected` group, each saying more precisely why an application closed: `Declined - Credit policy`, `Declined - Insufficient docs`, `Client declined - Not interested`, `Client declined - Already funded` and `Unable to reach`. - 1.1.0: An optional `reason` on `applicationDeclined` and `applicationWithdrawn`, and on GET for a closed application: a plain English sentence, present when GreyRok recorded one. - 1.1.0: `applicationFunded` is no longer always the last message. If the facility is lost after the client accepted, one `applicationDeclined` or `applicationWithdrawn` follows. - 1.1.0: An application closed because requested information or documents never arrived is now sent as `applicationDeclined` with `Declined - Insufficient docs`. In 1.0.0 the same outcome arrived as `applicationWithdrawn` with `Client declined - No longer required`. ## Rules an integration gets wrong These are the mistakes made most often. Each one is enforced or true at runtime and none is inferable from the OpenAPI document. - Amounts above the published product range are ACCEPTED, not refused. GreyRok Capital publishes $5,000 to $500,000; a request above it is assessed by a credit assessor. Do not filter on an upper bound and do not write a handler for a 422 that will not arrive. Below $5,000 IS refused, and so is anything above $25,000,000, which exists to catch a misplaced decimal. - Accepting a submission is not an indication of the outcome. A 201 means the application was recorded, nothing more. - whoToCall is optional, but once sent it brings a requirement the OpenAPI document cannot express: "broker" needs the broker block (name and phone), and "client" needs callOnBehalfOf. Either missing is a 422 at that field. The answer is shown to the GreyRok Capital credit team, as your request, in the new application email and on the deal. It is a request to a person, not a setting any system enforces: GreyRok Capital may still contact the applicant directly, for example to complete the full application. - A status webhook answered with a 3xx, or any 4xx other than 408 and 429, is DROPPED after one attempt with no notification. Answer 200 on receipt, or 503 while deploying. Never 403. - Each applicationId with eventType is delivered at most once per application. A second internal transition mapping to an event already sent produces nothing. Deduplicate on that pair; do not expect a message per state change. - externalRef is unique across BOTH environments, which share one record. Suffix test references or they will collide with live ones. - There is never a commission figure of any kind. Not on any event, including funded. Do not map fields for commissionPercentageRate, commissionPaidExGst or commissionPaidIncGst; GreyRok Capital does not hold them. - applicationFunded carries approvedLoanAmount, the amount the facility funded at, in whole dollars, whenever GreyRok Capital holds it. It can differ from requestedLoanAmount. When it is not held the key is absent, never zero or null. - A declined or withdrawn event may carry `reason`: a plain English sentence saying why the application closed, present only when it was recorded. Show it to a person as it is. Switch on statusName, never on reason: the wording is written for brokers and may be improved without notice. - applicationFunded is final unless the facility is later lost. If a funded deal falls over, exactly one applicationDeclined or applicationWithdrawn follows, and then nothing. Do not refuse a Rejected event for an application you hold as Funded. - Not every event reaches the webhook yet. applicationUnderAssessment produced by your applicant completing the full application is currently emailed, not POSTed, even to a partner on webhook only. The same event is POSTed when it comes from the GreyRok Capital credit team. Do not make a workflow wait on that webhook. - The eventType and statusName lists can grow within /v1, each time with a new version number. Handle a value you do not recognise by its `status` group. Do not write an exhaustive switch that refuses the message. - A key issued for the live base URL begins grk_test_. The prefix names the database the deployment reads, not the environment's purpose. It is correct. Do not treat it as a misconfiguration. - Timestamps are ISO 8601 and never month first, but the precision differs by field and a strict parser must accept both. `receivedAt` on a 201 and `lastModified` on a status event are UTC to the second, ending Z, for example 2026-09-17T00:43:45Z. `updatedAt` on a GET is the stored value at microsecond precision with a numeric offset, for example 2026-09-17T00:43:19.742081+00:00. Parse with a library, not a fixed-width slice. - A 422 lists at most 50 field errors and is truncated without a flag. Fix and resubmit rather than assuming the list is complete. ## Environments One API key works on both. Only the hostname changes. - LIVE: https://partners.greyrokcapital.com.au/api/partner/v1 Live. Applications submitted here reach the GreyRok credit team and are written to the CRM. - TEST: https://sandbox.greyrokcapital.com.au/api/partner/v1 Sandbox. Shares a database, and so your partner record and webhook URL, with the live base URL. No application submitted here is emailed to the credit team or written to the CRM. Measured: a submission there records the CRM write as dry_run and every email as skipped. It is not cleared on a schedule, so references are durable and real applicant data must not be sent to it. - DOCUMENT UPLOADS (both environments): https://qhjgawbbbrrcmlgvkwkj.supabase.co/functions/v1/partner-documents A different host on purpose: it accepts 25 MB where the main one rejects anything over roughly 4.5 MB. Same API key. ## Endpoints Authentication on every request: `Authorization: Bearer `. POST /applications Submit an application. 201 with { success, reference, externalRef, status, receivedAt, statementsRequired }. `reference` is GRK-DDMM-NNNN and identifies the deal in every later exchange. Request body limit 256 KB. Rate limit 300 per hour, this endpoint only. GET /applications/{reference} Read one application back. 200 with { success, reference, externalRef, status, statusGroup, description, updatedAt, requestedLoanAmount, approvedLoanAmount?, reason? }. `approvedLoanAmount` is present only on a funded application whose amount GreyRok holds, the figure its funded event carried. `reason` is present only on a closed application whose reason was recorded, in the same words the closing event carried. Scoped to your own submissions: another partner's reference answers 404, identically to one that does not exist. The value can lag the real state, because states a partner cannot act on are reported as the received mapping. POST https://qhjgawbbbrrcmlgvkwkj.supabase.co/functions/v1/partner-documents/applications/{reference}/documents multipart/form-data with `file`, optional `documentType` and `description`. 25 MB per file. Re-uploading the same file answers 200 with duplicate: true rather than storing it twice. ## Request body Generated from the validator. `required` here means the API refuses the request without it. ### Top level - externalRef: string; required; 1 to 64 characters, no line breaks or control characters The partner's own reference for this application. Unique per partner. Returned on every status update so both systems can identify the same deal. - whoToCall: enum; optional; one of: client | broker Who you would like the GreyRok credit team to call about this application: "client" (the applicant) or "broker". When "broker", the broker block is required. When "client", callOnBehalfOf is required. Shown to the credit team as your request, in the new application email and on the deal. It is a request, not a setting: GreyRok may still contact the applicant directly, for example to complete the full application. When omitted, no preference is shown. - callOnBehalfOf: string; optional; up to 100 characters, no line breaks or control characters Who you would like GreyRok to say it is calling on behalf of when it calls the client, as in "Hi, this is GreyRok calling on behalf of ABC Finance". Required when whoToCall is "client". - notes: string; optional; up to 2000 characters, no control characters Anything the broker wants the credit team to read. Shown to the credit team as written, line breaks included, in the new application email and on the deal. ### Facility (facility) - amountRequested: number; required; 5,000 to 25,000,000 Requested facility amount in whole Australian dollars. An amount carrying cents is rounded to the nearest dollar rather than refused. Amounts above GreyRok's published range are accepted and assessed; acceptance is not an indication of the outcome. - purpose: enum; optional; one of: equipment | inventory | growth | cashflow | supplier | other What the finance is for. One of the listed keys, which map to: equipment (Equipment), inventory (Inventory), growth (Growth), cashflow (Cashflow), supplier (Supplier terms), other (Other). - guaranteeOffered: boolean; optional Whether the directors offer a personal guarantee. GreyRok requires one on most facilities, and false does not by itself decline an application. ### Business (business) - abn: string or null; optional; up to 20 characters Australian Business Number. Eleven digits, spaces permitted, and the check digit must be arithmetically valid. Optional: send it and GreyRok reads the entity name and the registration date off the Australian Business Register for you, so it is one field instead of two. Omit it, send null or send an empty string where the business does not have one, and supply business.entityName and business.tradingSince yourself instead. GreyRok confirms registration against the register separately, so a valid ABN here is not a verified one. - entityName: string; optional; 1 to 200 characters, no line breaks or control characters Registered entity name. Optional only when business.abn is supplied, because GreyRok reads it off the Australian Business Register. Required when the ABN is omitted. - tradingName: string; optional; up to 200 characters, no line breaks or control characters Trading name, where it differs from the entity name. - entityType: enum; optional; one of: Australian private company | Sole trader | Partnership | Discretionary trading trust | Unit trust | Other incorporated entity - industry: enum; optional; one of: Trades | Professional services | Healthcare | Manufacturing | Wholesale | Transport / logistics | Retail | Hospitality | Construction | Agriculture | Other The industry the business trades in, defaulting to `Other` when omitted. - tradingSince: string (date); optional; YYYY-MM-DD Date the business was registered or began trading, as YYYY-MM-DD. GreyRok derives its trading history band from this date, so no band needs to be chosen. Optional only when business.abn is supplied, because GreyRok reads the registration date off the Australian Business Register. Required when the ABN is omitted. It must not be in the future, which JSON Schema cannot express and this document therefore states here. - monthlyRevenue: number; required; 1 to 1,000,000,000 Average monthly revenue in whole Australian dollars, over the last six months. This is monthly, not annual. ### Business address (business.address), optional block Registered business address. Optional at submission; GreyRok collects it during assessment when it is not supplied. - street: string; required; 1 to 160 characters, no line breaks or control characters - suburb: string; required; 1 to 80 characters, no line breaks or control characters - state: enum; required; one of: NSW | VIC | QLD | WA | SA | TAS | ACT | NT - postcode: string; required Four digits. ### Applicant (applicant) The client's contact: the person at the business GreyRok would speak to about this application. Not the broker, who goes in broker. - firstName: string; required; 1 to 80 characters, no line breaks or control characters - lastName: string; required; 1 to 80 characters, no line breaks or control characters - email: string; required; 1 to 254 characters - mobile: string; required; 1 to 24 characters Australian mobile or landline. Accepted in any of these forms: 0412345678, +61 412 345 678, +61412345678, 0061412345678, 412345678. Stored in national 10 digit form. - role: string; optional; up to 80 characters, no line breaks or control characters The applicant's role in the business. - isDirector: boolean; optional Whether the applicant is themselves a director of the entity. Defaults to true when omitted. ### Broker (broker), optional block The broker who introduced this application. Required when whoToCall is "broker". Shown to the GreyRok credit team in the new application email and on the deal. - name: string; required; 1 to 100 characters, no line breaks or control characters The broker's full name. - phone: string; required; 1 to 24 characters The broker's Australian mobile or landline. Accepted in any of these forms: 0412345678, +61 412 345 678, +61412345678, 0061412345678, 412345678. Stored in national 10 digit form. A 13, 1300 or 1800 number is not accepted. ### Directors and guarantors (directors[]), optional block - firstName: string; required; 1 to 80 characters, no line breaks or control characters - lastName: string; required; 1 to 80 characters, no line breaks or control characters - role: string; required; 1 to 80 characters, no line breaks or control characters - email: string; required; 1 to 254 characters - mobile: string; required; 1 to 24 characters Australian mobile or landline. Accepted in any of these forms: 0412345678, +61 412 345 678, +61412345678, 0061412345678, 412345678. Stored in national 10 digit form. - dateOfBirth: string (date); required; YYYY-MM-DD Date of birth as YYYY-MM-DD. It must not be in the future. - ownershipPercent: integer; required; 0 to 100 Percentage of the entity this director owns. The directors array must not total more than 100. - citizenship: enum; required; one of: Australian citizen | Permanent resident | Neither - homeowner: enum; required; one of: Own with a mortgage | Own outright | Renting | Living with family | Other - politicallyExposed: enum; required; one of: No | Yes | Unsure Whether this director is a politically exposed person. Required under GreyRok's AML and CTF obligations. ### Director residential address (directors[].address) Residential address, not the business address. - street: string; required; 1 to 160 characters, no line breaks or control characters - suburb: string; required; 1 to 80 characters, no line breaks or control characters - state: enum; required; one of: NSW | VIC | QLD | WA | SA | TAS | ACT | NT - postcode: string; required Four digits. ### Consent (consent) The partner's assertion that the applicant consented. GreyRok records this as the partner's statement, with its timestamp and method, and relies on it under the partner agreement. - obtained: boolean; required; must be true Must be true. GreyRok cannot assess an application without the applicant's consent to collect and disclose their credit information. - obtainedAt: string (date-time); required; ISO 8601, offset accepted When consent was obtained, as an ISO 8601 timestamp. An offset is accepted, so 2026-09-11T14:12:00+10:00 and 2026-09-11T04:12:00Z are both valid. It must not be in the future. - method: enum; required; one of: broker_portal | online_form | phone_recorded | written | other How consent was obtained. - methodDetail: string; optional; up to 200 characters, no line breaks or control characters Required when method is "other". Ignored otherwise. - applicantIp: string; optional; up to 45 characters The applicant's IP address at the moment consent was given, where the partner captured it. Strengthens the record and is not required. ### Documents (documents), optional block - illionDocumentIds: string[]; optional; up to 20 entries illion document references for bank statements the broker already collected. GreyRok stores these against the application. Retrieval is arranged with illion directly and is not yet automated, so supplying them does not remove a statements request. ## Errors A 422 body, which is the shape to parse: { "success": false, "errors": [ { "field": "facility.amountRequested", "error": "Our minimum facility is $5,000." } ] } A 409 carries the reference already held, so a retry after a dropped connection is safe and tells you what happened the first time: { "success": false, "error": "This reference has already been submitted.", "reference": "GRK-1209-4471", "externalRef": "..." } Authentication failures are byte-identical whatever the cause: { "success": false, "data": { "error": "Invalid credentials" } } 400 body unreadable as JSON. 401 no credentials. 403 credentials not recognised, revoked, suspended or from the other environment. 404 no such application in your account, or the wrong host. 405 wrong method on the upload endpoint. 413 body over 256 KB or file over 25 MB. 429 rate limited, Retry-After in seconds. 502 not recorded, safe to retry with the same externalRef. 503 maintenance, wait for Retry-After. Only 502 and 503 are worth retrying unchanged. ## Status events 11 events, 16 status names. Each event is emailed to your nominated address unless you have asked for webhook only, and POSTed to your URL if you supply one, except that applicationUnderAssessment from your applicant completing the full application is currently emailed and not POSTed. Rejected is final: after it, nothing further arrives for that application. Settled is final unless the facility is later lost, in which case exactly one Rejected event follows. - applicationReceived: status="In Progress", statusName="Application with credit team" Application received and with the GreyRok credit team. - applicationUnderAssessment: status="In Progress", statusName="Work in progress" Full application received and under assessment. - documentsRequested: status="In Progress", statusName="Docs requested" Further documents have been requested from the client. - applicationInCredit: status="In Progress", statusName="Waiting for credit to approve" Application submitted to the GreyRok credit team for a decision. - applicationApproved: status="In Progress", statusName="Approved" Application approved by the GreyRok credit team. - contractSent: status="In Progress", statusName="Agreement sent to client" The loan agreement has been sent to the client to sign. - contractSigned: status="In Progress", statusName="Agreement signed" The client has signed the loan agreement. - pendingSettlement: status="In Progress", statusName="Pending settlement" Final checks are under way before the facility is funded. - applicationDeclined: status="Rejected", statusName="Declined - General" (TERMINAL) Application declined. reason: absent, or one of "Declined following credit assessment" | "Did not pass our verification checks" | "Material change before funding" | "Other" - applicationDeclined: status="Rejected", statusName="Declined - Credit policy" (TERMINAL) Application declined. reason: "Outside our lending criteria" - applicationDeclined: status="Rejected", statusName="Declined - Insufficient docs" (TERMINAL) Application declined. reason: "Requested information or documents were not provided" - applicationFunded: status="Settled", statusName="Funded" (final unless later lost) Facility funded. - applicationWithdrawn: status="Rejected", statusName="Client declined - No longer required" (TERMINAL) Application closed. It was not declined by the GreyRok credit team. reason: absent, or "The client withdrew the application" - applicationWithdrawn: status="Rejected", statusName="Client declined - Not interested" (TERMINAL) Application closed. It was not declined by the GreyRok credit team. reason: "The client chose not to proceed" - applicationWithdrawn: status="Rejected", statusName="Client declined - Already funded" (TERMINAL) Application closed. It was not declined by the GreyRok credit team. reason: "The client obtained funding elsewhere" - applicationWithdrawn: status="Rejected", statusName="Unable to reach" (TERMINAL) Application closed. It was not declined by the GreyRok credit team. reason: "We were unable to reach the client" Every event carries these eight keys: applicationId, status, statusName, eventType, description, lastModified, companyTradingName, requestedLoanAmount plus three that are not on every event: externalRef whenever GreyRok holds one: always on an application you submitted, absent on a test message reason on applicationDeclined and applicationWithdrawn, when it was recorded approvedLoanAmount on applicationFunded, when GreyRok holds the amount the facility funded at No others (a test message also carries test: true). requestedLoanAmount is the amount REQUESTED and may be null. approvedLoanAmount is the amount FUNDED, and can differ from it. ## Webhook delivery - When you have given us a secret, every update is sent with Authorization: Bearer . With no secret, no Authorization header is sent. - It is the secret itself over HTTPS, not a signature; the body is not signed. Compare it with the secret you gave us before acting on a message. - A secret is 16 to 200 printable ASCII characters with no spaces. - A test message, which we may send while your endpoint is being set up, carries test: true, names no real application, has no externalRef and may carry your secret. Answer 200 and discard it. - 10 second timeout. Redirects are not followed; a 3xx is a failure. - Retried on 5xx, 408, 429 and no response: up to 6 attempts in all, the first and then one after each of 5, 15, 60, 240, 720 minutes. A scheduled job sends the retries, so each can arrive later than its interval. - Any other answer is dropped after one attempt, silently. - Reconcile anything you believe you missed with GET /applications/{reference}.