In unix user space programs, you are dealing with two separate groups of api's. User programs call interfaces in the kernel (to do things that require kernel privilege, like doing i/o, on the user program's behalf) through the unix system library; and user programs can also call functions in the standard C library (and other userland libraries) which get linked into each user program. Typically, functions in the standard C library will themselves call the system library to access the kernel when required. Calling a system library function involves a privilege transition, whereas calling a C library function does not. The system library API, also known as the POSIX system API, is defined in the C header file <unistd.h>, and you need to include that header file in your program to call the system library correctly.
The unix system library contains a set of entry points which are called 'system calls' in usual terminology. However, the 'true' system calls in unix are the kernel interfaces that the system library itself, calls internally; each call being identified by a system call number. This is somewhat analgous to the MS-DOS INT 21H mechanism, where you have a preamble that loads some values into registers (or whatever parameter passing mechanism is used), one of which is the system call number, and then it calls a software interrupt (or similar mechanism) to pass control to the kernel; and finally passes any return information back to user space. The low-level interface is documented in section 3 here
https://docs.freebsd.org/en/articles/x86-assembly/ . The list of system call numbers is found in the file /usr/include/sys/syscall.h, and the corresponding system call names are defined in /usr/src/sys/kern/syscalls.c. There is a useful table of freebsd system calls here:
https://alfonsosiciliano.gitlab.io/posts/2026-04-09-freebsd-16-system-calls.html . As you can see, there are quite a lot of them, some obsolete. The system library may not provide callable functions for every available system call (see note on syscall(2) below), which is the reason for the distinction drawn between the set of interfaces provided in the system library through unistd.h, and the set of real or 'true' system calls supported by the operating system. Most of the the time, its a 1:1 mapping, however, so it's normal to use the term 'system call' to mean an entry point in the system library.
You can make low-level system calls directly in unix, but it doesn't gain you anything in performance terms, since the code you write to do the job merely replicates what is already in the unix system library; and if you want your code to stay easily maintainable, it's better to use the system library, since doing it yourself exposes you to the details of the low-level ABI. There's a good description here
https://en.wikipedia.org/wiki/System_call
- see the section headed "the library as an intermediary".
So for example, you would call write(2) and read(2) in the system library to call the system calls to write and read to/from a file descriptor, bypassing the C stdio library buffered i/o. The corresponding higher level C stdio library functions that do buffered i/o are fwrite(3) and fread(3); and those will internally call write(2) and read(2) respectively. Note that the system library calls are documented in section 2 of the manpages, and the C stdio (and other userland) library calls are documented in section 3 of the manpages; so you would say 'man 2 read' to see the manpage for read(2), and 'man 3 fread' to see the manpage for fread(3). And 'man 2 intro' gives you an introduction to the parameters that can be passed to system library calls, and describes the system library error handling.
Occasionally (not very often) there can be some system calls which do not have wrappers in the system library, in which case you need to use the syscall(2) mechanism to call them indirectly, by their system call number, in a standardised way; of course syscall(2) is itself an entry point into the system library.
In general, in user-space application programs, it is desirable to use the highest level calls available (eg, the standard C library) in preferrence to calling the system library directly, unless there is a specific reason to call the system library; doing so improves portability and provides access to additional facilities provided by the standard C library, saving code replication (eg, buffered i/o in the example discussed above). Code that your write on freebsd, that calls the standard C library, should be easy to port to other operating systems, whereas code that you write, that calls freebsd system calls through the system library, may not be so portable, depending upon what system calls you made; things like read(2) and write(2) are pretty much universally available and are specified by POSIX, whereas others may have different signatures on other operating systems, or may not even exist at all.
This is a short introductory overview, with lots of details omitted. For homework, look up 'non-blocking i/o', and 'restartable system calls'.